denylist: `?format=car` does not skip directly blocked CIDs
TL;DR: ?format=car responses can contain blocks whose CIDs are on the denylist.
Problem
Path resolution goes through the denylist, so a blocked root or blocked subpath returns 410 in every response format. The CAR export does not: GetCAR in boxo/gateway walks the DAG with the raw DAGService, so a directly blocked CID inside an allowed directory ends up in the CAR body.
Not a regression. The end-to-end case in TestContentBlocking was disabled in #10360 because 0.26 already shipped this way:
https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/test/cli/content_blocking_test.go#L119-L132
#10805 and ipfs/boxo#458 (200 plus a CAR header for paths the gateway cannot resolve) share the code path and the fix.
Status (September 2026)
Still reproduces on current master. The fix lives in boxo and nopfs; #10948 only carries the end-to-end tests.
Remaining work, in order:
- ipfs-shipyard/nopfs#50: move blocking to the blockstore and exchange so session fetches also go through the blocker (ipfs-shipyard/nopfs#34). Needs review and a tagged release.
- ipfs/boxo#1019: skip blocked blocks during CAR traversal and hold headers until the first block so 404/410 can still be sent. Needs a rebase on main, a green
remote-car-backendconformance job, a changelog entry, and a release. - #10948: bump boxo and nopfs, keep the CAR cases in
TestContentBlocking, add the changelog entry.
gateway-conformance already accepts 404 for unresolvable CAR paths (ipfs/gateway-conformance#244, ipfs/gateway-conformance#245), so no conformance change is needed.
Source: ipfs/kubo