Skip to content

Commit 5eeed9e

Browse files
test(wac): regression for POST-created .acl/.meta sidecar injection
Cover the privilege-escalation path fixed in this PR: an append-only agent (public inbox) POSTing Slug: victim.acl / victim.meta must get 403, a normal non-sidecar POST still gets 201, and the owner (Control) can still POST an .acl sidecar. The deny test fails against the unpatched handler and passes with the Control guard.
1 parent fbe9b77 commit 5eeed9e

1 file changed

Lines changed: 52 additions & 0 deletions

File tree

test/auth.test.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,58 @@ describe('Authentication', () => {
212212
const res3 = await request('/authuser1/authenticated-only/test.txt', { auth: 'authuser2' });
213213
assertStatus(res3, 200);
214214
});
215+
216+
it('should deny POST-created .acl/.meta sidecars without Control on the protected resource', async () => {
217+
// Regression for the POST .acl sidecar injection: an agent holding only
218+
// acl:Append on a container (here, the public-append inbox) must not be
219+
// able to plant a sidecar that governs a sibling resource's permissions.
220+
await createTestPod('sidecarvictim');
221+
222+
const aclBody = JSON.stringify({
223+
'@context': { acl: 'http://www.w3.org/ns/auth/acl#' },
224+
'@graph': []
225+
});
226+
227+
// Append-only (unauthenticated public append) agent tries to plant victim.acl
228+
const attackAcl = await request('/sidecarvictim/inbox/', {
229+
method: 'POST',
230+
headers: { 'Content-Type': 'application/json', 'Slug': 'victim.acl' },
231+
body: aclBody
232+
});
233+
assertStatus(attackAcl, 403);
234+
235+
// The same trick with a .meta sidecar must also be blocked
236+
const attackMeta = await request('/sidecarvictim/inbox/', {
237+
method: 'POST',
238+
headers: { 'Content-Type': 'application/json', 'Slug': 'victim.meta' },
239+
body: aclBody
240+
});
241+
assertStatus(attackMeta, 403);
242+
243+
// A normal (non-sidecar) POST to the public inbox still works
244+
const legit = await request('/sidecarvictim/inbox/', {
245+
method: 'POST',
246+
headers: { 'Content-Type': 'application/json', 'Slug': 'note' },
247+
body: JSON.stringify({ type: 'note' })
248+
});
249+
assertStatus(legit, 201);
250+
});
251+
252+
it('should allow the owner (Control) to POST an .acl sidecar', async () => {
253+
// Owners hold acl:Control, so the sidecar guard must not block them.
254+
await createTestPod('sidecarowner');
255+
256+
const res = await request('/sidecarowner/', {
257+
method: 'POST',
258+
headers: { 'Content-Type': 'application/json', 'Slug': 'owned.acl' },
259+
body: JSON.stringify({
260+
'@context': { acl: 'http://www.w3.org/ns/auth/acl#' },
261+
'@graph': []
262+
}),
263+
auth: 'sidecarowner'
264+
});
265+
assertStatus(res, 201);
266+
});
215267
});
216268

217269
describe('WAC-Allow Header', () => {

0 commit comments

Comments
 (0)