# Decide whether a bulk export fix is ready

Use the complete synthetic fixture below in a notebook or text file. No live target, paid service or secret is needed. Make your own decision before opening the worked assessment. Then take the implementation option below, a local project in which you repair running code until its tests pass, and keep its test output with your written answers.

A team fixed its ordinary invoice endpoint, but is asking you to approve an export release. Build a finding, regression plan and release decision from the supplied evidence.

## Supplied material

```text
Release candidate: source r42, artifact sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.
Policy: authenticated users may export only invoices they own in their active tenant. A finance-admin role may export all invoices in that tenant only.
Alice = north ordinary user; Bob = north finance-admin; Eve = south ordinary user.
Rows: n1 belongs Alice/north; n2 belongs another north user; s1 belongs Eve/south.
GET /invoices/n1 performs a server-side ownership check.
POST /exports takes tenantId and columns from JSON. Worker query filters by tenantId from that JSON. Cache key is 'export:'+requested format. Worker runs as a privileged service.
Observed authorized test: Alice requests north/pdf and gets n1,n2; Eve then requests south/pdf and receives the cached north document.
CI record T19 passed on r41/artifact bbbb…; r42 adds the export cache. The r42 build also contains library parsekit 2.4.0. The supplied synthetic advisory affects parsekit below 2.4.1 when XML external entity parsing is enabled. This export consumes JSON and produces PDF; there is no complete call-path inventory yet.
Webhook event export-paid-9 is retried after the export worker times out.
```

## Task 1

Trace API→queue→worker→cache→download and identify where authority must be carried and checked.

Your assessment:

## Task 2

Write a reproducible two-tenant finding and a minimum positive/negative test matrix including cache order reversal.

Your assessment:

## Task 3

Assess the dependency record without claiming the JSON path proves the vulnerable XML code is unreachable everywhere.

Your assessment:

## Task 4

Specify a release gate and durable handling of the retried event; decide whether the supplied evidence justifies shipping.

Your assessment:

## Decide the fixed cases

### Which invoices may each person export under the policy?

Choose from: n1 only; n1 and n2; s1 only; n1, n2 and s1.

- Bob, north finance-admin: ______
- Alice, north ordinary user: ______
- Eve, south ordinary user: ______

### Decide the release questions.

Choose from: Yes; No.

- Can candidate r42 ship on the supplied evidence?: ______
- Does CI record T19 count as evidence for r42?: ______
- Can parsekit 2.4.0 be labeled not affected because this export uses JSON?: ______

## Evidence

- Finding with impact, exact synthetic requests, affected candidate and causal chain.
- Actor/role/object/cache test plan plus worker authorization checks.
- Dependency applicability record separating known, unknown and next evidence.
- Release decision naming blocking evidence and responsible roles.

## Rubric

Score each criterion with the anchor whose evidence your answer shows: 0, 1 or 2 points. Every anchor describes something a reviewer can point to in your work. Aim for at least 7 of 8, with no unresolved critical failure.

### 1. Finding connects API, worker and cache causes to observed disclosure. (2 points)

- 0 points: Reports “IDOR in exports” with no request sequence, or blames a single component.
- 1 point: Names the tenantId taken from the JSON body and the shared cache key, but leaves out the privileged worker or the same-tenant bypass (Alice receiving n2).
- 2 points: A reproducible finding: Alice’s north/pdf request returns n1 and n2 (ownership bypass), then Eve’s south/pdf request receives the cached north document. It traces both to the caller-supplied tenantId, the worker reading with its own authority and the “export:”+format cache key, and names candidate r42 and its artifact digest.

Your score:

### 2. Tests include legitimate finance-admin access and both tenant/ownership denials. (2 points)

- 0 points: Only denial tests, or a plan that a deny-all change would pass.
- 1 point: Includes Bob’s legitimate export and a cross-tenant denial, but not the same-tenant ownership case or the reversed cache order.
- 2 points: The matrix has Bob exporting n1 and n2, Alice receiving only n1, Eve only s1, and Eve’s request naming tenant north refused, each run in both cache orders, plus a worker-level check that the job carries and enforces the requester’s identity.

Your score:

### 3. Dependency status and test provenance preserve uncertainty and candidate identity. (2 points)

- 0 points: Marks parsekit not affected because the export uses JSON, or counts T19 as evidence for r42.
- 1 point: Keeps parsekit under investigation, or notes that T19 ran on r41, but does not say what evidence would settle it or what must run again.
- 2 points: The record says parsekit 2.4.0 ships in r42 and is in the advisory range, and stays under investigation until every deployed path and the XML external-entity setting are accounted for or the library is upgraded to 2.4.1. T19 is tied to r41 and artifact bbbb… and must run again on r42 and artifact aaaa….

Your score:

### 4. Release gate and retry handling name decisive evidence and accountable owners. (2 points)

- 0 points: Approves the release, or blocks it without saying what would unblock it.
- 1 point: Blocks r42 and lists the missing tests, but names no owners, or treats the retry of export-paid-9 as a new billing event.
- 2 points: Blocks r42 until the repaired build passes the matrix and the dependency record is resolved; every item has an accountable role; export-paid-9 is keyed by its event ID so a retry returns the original outcome without a second charge.

Your score:

Critical failures (resolve before calling the case complete):

- [ ] Ships based on the r41 test record.
- [ ] Treats the worker service credential as authorization for every user request.

## Implementation option: Build and verify a signed software release

Build the release, then repair the consuming gate in exercise.mjs until all 20 tests pass, so evidence about one artifact can no longer approve another: the T19-on-r41 mistake in this case.

Keep: Failing and passing test output, and the test that rejects evidence bound to a different artifact digest, mapped to your release decision.

Download: https://softwaresecurity.com/downloads/projects/release-verification-bd914fcbede61c32.zip (Node.js 22+ · no dependencies, 20 tests). Instructions: https://softwaresecurity.com/labs/#project-release-verification

## Worked assessment (read after completing the case)

Block the candidate on tenant disclosure and same-tenant ownership bypass. The worker needs trusted actor/tenant/action context and authorization at the actual read/download boundary; a broad service credential does not inherit the user’s permissions. Cache separation must reflect the authorized result audience and invalidation policy, or private exports should bypass shared cache. Bob may export n1,n2 for north, Alice n1 only, and Eve s1 only. T19 is for another artifact and cannot close r42. The dependency remains under investigation until deployed paths/configuration are accounted for; do not label it not affected merely because the reviewed endpoint uses JSON. Retried events must not create duplicate billing effects.

Original teaching material: CC BY 4.0. Attribution: Software Security.
