# The container was serving our own source: evidence note

Date: 2026-09-17

This note supports the /record entry source-exposure-001 and the piece at
/writing/the-container-was-serving-our-own-source.

What happened. On 2026-09-17 a technical SEO audit of the live site (a6c54ec9)
found F2: the production container was serving the repository at the web root. A
request to /scripts/build.py returned HTTP 200 with 15,152 bytes of real source.
F2 listed eleven probed paths. Eight returned 200 with real content:
/scripts/build.py, /scripts/pages.py, /deploy/nginx.conf, /tests/test_build.py,
/journal.json, /template.html, /README.md and /.github/workflows/journal.yml.
Three returned 404, correctly excluded by .dockerignore: /Dockerfile, /.gitignore
and /.dockerignore. The audit scored F2 MEDIUM, because a security finding inside
a search audit takes the audit's scale, and because the rendered page showed
nothing. The cause was one line in the Dockerfile,
COPY --from=journal /src /usr/share/nginx/html. Independent verification
(1eeb9f9e) confirmed all eleven probed paths behaved exactly as reported.

The change. A1 (ecd9f09e) narrowed the runtime copy to the public set: the index,
thesis, how-it-works, team, investors and 404 pages, plus the record directory,
the evidence directory, the sitemap, robots, llms and the favicon. nginx denies
the internal prefixes as a second layer, so a file that reaches the image is
still not served. The regression tests were added as A10 and verified
independently (4bf6f023, with 3ae991d8) at commit b143215 (private repository),
using a clean clone and a real nginx with the internal files planted on disk, so
the check tests the rule rather than the file list. A11, a favicon-href fix from
the same verification pass, is separate from the exposure. Deployment 4f9841a2 at
commit 331bed10 (private repository) succeeded at 2026-09-17T14:34:32Z; the
post-deploy check (52671161) confirmed the exposure closed live, with the
internal paths that returned 200 before the fix now returning 404 with the
12,448-byte 404 page, while /evidence/direction.md and
/evidence/state-is-the-product.md still serve at 629 bytes and 966 bytes. The
suite grew from 16 tests to 22 at b143215.

Sources. Audit a6c54ec9 F2; independent verification 1eeb9f9e; fix ecd9f09e; fix
verification 4bf6f023 with 3ae991d8; deployment 4f9841a2 at commit 331bed10;
post-deploy check 52671161; gate a84b97b3.

Limit. When the exposure began is not established, because the Dockerfile's
change history was not read, so only the end of the window is known. Whether any
crawler or person fetched an internal file is unknown, because no access logs
were available; the evidence proves the paths were public, not that anyone read
them. And eleven paths were probed rather than the tree enumerated, so the
reachability of the whole tree follows from the copy line and is not a count. The
origin configuration is inferred from the committed deploy/nginx.conf plus
matching live behaviour, because only edge behaviour is observable.
