Hi everyone,
I'm investigating a POST request to the following endpoint in our AEM as a Cloud Service environment:
POST /content/dam/<project>/it/folder.bulkassets.delete
From the Developer Console, I can see it's handled by the standard servlet:
com.day.cq.dam.commons.ui.impl.servlets.BulkDeleteServlet
(from the com.day.cq.dam.cq-dam-commons bundle).
I'm trying to understand what UI action triggers this servlet. I expected it to be related to selecting multiple assets in the DAM console and clicking "Delete", but when I perform that action, I only see requests to /bin/wcmcommand.
Has anyone seen this servlet in action? Specifically:
Any insights or experiences would be greatly appreciated. Thanks!
Solved! Go to Solution.
Views
Replies
Total Likes
Thanks to everyone who contributed to this thread!
After further investigation, I was able to identify the root cause of the bulkassets.delete request we observed.
This explains why the request wasn't reproducible in simpler test cases — the servlet is only invoked under specific conditions involving pagination and bulk selection.
Thanks again for all the insights and support — this was extremely helpful!
Hi @davidef34326447,
Despite its name, the /folder.bulkassets.delete
POST endpoint is not the one triggered when you delete assets via the standard DAM Admin (Touch UI) console using the "Delete" action from the toolbar. That deletion typically goes through:
POST /bin/wcmcommand
with cmd=deletePage
or for assets:
POST /bin/asynccommand
So, the BulkDeleteServlet
is not the servlet used when you just select assets in the UI and hit "Delete".
What Triggers It Then?
Legacy or Custom UIs
The endpoint /content/dam/<path>/folder.bulkassets.delete
is tied to internal APIs sometimes used by:
Classic UI
Custom or legacy tools/scripts built on top of the AEM DAM APIs.
Custom Workflows or Scripts
It can be invoked programmatically via HTTP clients, CURL, or JS-based automation, typically when you want to perform batch deletions in a controlled way (e.g., from a dashboard or automated cleanup tool).
Assets HTTP API (in some setups)
Depending on how AEM is configured, some older Asset HTTP APIs (or custom wrappers around them) might call this endpoint to handle bulk delete operations, especially for folder-level actions.
Try to test
You can simulate it with something like:
curl -u admin:admin -X POST \
-F ":operation=folder.bulkassets.delete" \
-F "path=/content/dam/myproject/it/folder-to-delete" \
http://localhost:4502/content/dam/myproject/it/folder.bulkassets.delete
This should trigger the BulkDeleteServlet
to delete the assets in that folder.
Hope that helps!
Hi @davidef34326447,
It might be possible, com.day.cq.dam.commons.ui.impl.servlets.BulkDeleteServlet is probably registered via the path /bin/wcmcommand
were you able to check its implementation as well?
Views
Replies
Total Likes
Thanks a lot for the detailed replies — they’ve been really helpful in clarifying the typical use cases for the bulkassets.delete endpoint.
To follow up:
Given that, I’m still unsure what exactly triggered the original bulkassets.delete POST we observed in our logs. It doesn’t seem to be tied to any standard UI interaction that I can reproduce.
Would it make sense at this point to open a ticket with Adobe Support to help trace the origin of that request? Has anyone done that before for similar cases?
Thanks again for the insights!
Views
Replies
Total Likes
Hi @davidef34326447 ,
Try below steps:
1. Custom HTTP Request (Programmatic Trigger)
You or some tool may have issued this POS
curl -u admin:admin -X POST \
-F ":operation=folder.bulkassets.delete" \
-F "path=/content/dam/<project>/it/folder-to-delete" \
https://<aem-host>/content/dam/<project>/it/folder.bulkassets.delete
This is often embedded in:
- Legacy automation scripts
- Custom admin tools or dashboards
- Bulk asset cleanup jobs
2. Custom Workflow Step (ECMA or Java)
Some AEM projects create custom workflow steps that call this endpoint from a script step.
Example:
var url = "/content/dam/myproject/it/folder.bulkassets.delete";
var params = {
":operation": "folder.bulkassets.delete",
"path": "/content/dam/myproject/it/folder-to-delete"
};
submitPost(url, params);
Check:
- Workflow models under /conf, /var/workflow/models
- Workflow history in /var/workflow/instances
- For ECMA scripts or Java steps calling this
3. Legacy Admin Console (Classic UI)
In AEM Classic UI (older consoles), this servlet was used for batch asset deletions directly.
Not used in AEM Touch UI or Universal Editor today.
Why You Saw This in Logs but Can’t Reproduce
This happens when:
- A custom job or external automation invoked it silently
- A manual API test was done and forgotten
- A backend scheduled process (Java, Groovy, or AIO App Builder) executed it
Step 1: Search Logs
Search the AEM publish logs (error.log, request.log) for the exact endpoint:
grep "folder.bulkassets.delete" error.log
grep "bulkassets.delete" request.log
You’ll see something like:
POST /content/dam/myproject/it/folder.bulkassets.delete HTTP/1.1
User-Agent: curl/7.79.1
Referer: internal-tool
Check:
- User-Agent
- Referer header
- User ID used
To trace who/what triggered it.
Step 2: Simulate It Locally for Testing
curl -u admin:admin -X POST \
-F ":operation=folder.bulkassets.delete" \
-F "path=/content/dam/we-retail/en/products/shirts" \
http://localhost:4502/content/dam/we-retail/en/products.bulkassets.delete
You’ll see all assets in the shirts folder get deleted.
@Component(service = Filter.class,
property = {
"sling.filter.scope=REQUEST",
"sling.filter.pattern=/content/dam/.*/folder\\.bulkassets\\.delete"
})
public class BulkDeleteSecurityFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String userId = req.getRemoteUser();
if (!userId.equals("admin")) {
((HttpServletResponse) response).sendError(403, "Forbidden");
return;
}
chain.doFilter(request, response);
}
}
Regards,
Amit
Views
Replies
Total Likes
Hi Amit, thanks — very interesting insights.
Just to clarify: we’re on AEM as a Cloud Service, and I’m not sure if Classic UI is even available in our setup.
Here’s what I’ve found so far:
Access logs show the following request:
<POD-instance> <IP address> <user email> [26/May/2025:10:04:28 +0000]
"POST /content/dam/<project>/it/folder.bulkassets.delete HTTP/1.1" 200 2569
"<author-instance>/assets.html/content/dam/<project>/it/folder"
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0"
Error logs show:
[26/May/2025:10:04:29.002] [<POD-instance>] *INFO* [<IP address> POST /content/dam/.../folder.bulkassets.delete]
com.adobe.cq.dam.assethandler.internal.events.delete.impl.AssetDeleteHandler
Got delete event. name: null, path: /content/dam/.../<deleted-resource>, type: preDelete
CDN logs confirm the same request with:
From the CDN log, it appears the request came from the same user agent as standard UI interactions — not sure if that sparks any ideas on your end.
At this point, I’m not interested in manually triggering the call (as in your step 2), but rather in understanding who or what triggered it, since I haven’t been able to reproduce it through any UI or workflow.
Interestingly, I found similar traces on four different days over the past 15 days of logs — which suggests it may not be an isolated event.
Your point 3 about securing the endpoint is very useful — I’ll definitely consider implementing that if we can’t identify the source.
In the meantime, I’ve also opened a ticket with Adobe Support to help investigate further.
Thanks again for your help!
Views
Replies
Total Likes
Following further investigation, I performed a reverse engineering of the client-side JavaScript libraries and discovered that the bulkassets.delete selector appears in two Adobe-provided JS files:
/libs/dam/gui/coral/components/admin/clientlibs/actions.*.js
Contains the line:
k.bulkDeleteData ? (E = k.bulkDeleteData.sourceParentPath + ".bulkassets.delete", ...
This strongly suggests that the bulkassets.delete endpoint is dynamically constructed and used when certain bulk deletion conditions are met.
/libs/cq/gui/components/common/wcm/clientlibs/wcm.*.js
Contains:
var selector = activator.hasClass("cq-damadmin-admin-pasteasset") ? "bulkassets" : "bulkpages";
Based on this, it seems likely that the first script is responsible for triggering the bulkassets.delete call — possibly under specific UI conditions or user actions that we haven’t yet reproduced.
I’m currently trying to trace the exact UI flow or interaction that leads to this code path being executed.
Let me know if you have any internal documentation or insight into how and when this JS logic is expected to be triggered in AEM as a Cloud Service.
Thanks again for your support.
Views
Replies
Total Likes
Thanks to everyone who contributed to this thread!
After further investigation, I was able to identify the root cause of the bulkassets.delete request we observed.
This explains why the request wasn't reproducible in simpler test cases — the servlet is only invoked under specific conditions involving pagination and bulk selection.
Thanks again for all the insights and support — this was extremely helpful!
Views
Likes
Replies