Skip to content

fix(server): stop two endpoints echoing exception text back over HTTP - #55

Merged
webdevsamran merged 5 commits into
mainfrom
fix/stack-trace-exposure
Sep 7, 2026
Merged

fix(server): stop two endpoints echoing exception text back over HTTP#55
webdevsamran merged 5 commits into
mainfrom
fix/stack-trace-exposure

Conversation

@webdevsamran

@webdevsamran webdevsamran commented Sep 7, 2026

Copy link
Copy Markdown
Owner

CodeQL reported two py/stack-trace-exposure alerts (medium). Both are real, though for different reasons.

/readyz — the one that matters

Unauthenticated, and it returned str(exc) from whatever the sqlite3 probe raised. A sqlite3 message carries the database path and often schema detail, handed to anyone who can reach the port. A readiness probe needs one bit; the detail now goes to the server's own log, where an operator can already see it.

/v1/jobs — the habit, not the leak

The enqueue handler returned str(exc) from QueueFull, whose message this codebase writes itself, so nothing untrusted was leaking today. The habit is still worth removing: the next exception to reach that handler may not be one we wrote. It now returns a fixed message plus max_active_jobs as a field — also easier for a client to act on than parsing prose.

What keeps it fixed

A new test makes /readyz fail with an error message containing a database path, then asserts the response body contains neither the path nor the error text.

Verification

Gate Result
ruff check / ruff format --check clean
mypy clean, 90 source files
pytest 412 passed

Two of the four Code of Conduct files pointed at GitHub features that are not
real:

- devrepro-doctor: report "via GitHub private message". GitHub has no private
  messaging.
- local-ai-hardware-bench: report by "opening a private issue tagged
  `conduct`". GitHub has private *vulnerability reports*; it has no private
  issues.

api-verity-lab gave a profile URL rather than a contact channel. Only
tooltrace-bench named an address that works. Someone reporting harassment is
the worst possible person to hand a dead end, so all four now carry the same
wording: the maintainer's noreply address plus GitHub's real report-abuse form.

Worse, and found while checking the above: all four SECURITY.md files direct
reporters to GitHub's private vulnerability reporting, and it was **disabled on
all four repositories**. Every documented security-disclosure path in this
family of projects led to a page the reporter could not use. It is enabled now
(a repository setting, so not visible in this diff).

The disclosure SLAs also disagreed for the same solo maintainer -- 72h, 72h+7d,
7d, and 7d+30d. Standardized on 7 days to acknowledge and 30 to update, the
most conservative of the four, and said plainly why: promising 72 hours when
nobody is on call is a promise, not a policy.

tests/test_contact_channels_exist.py pins this. It asserts the working address
and the report-abuse form are present, that SECURITY.md still names private
vulnerability reporting and still warns against public issues, and -- the point
of the exercise -- that no document mentions "private message", "private issue"
or "report-user functionality" again. Verified by reintroducing the
devrepro-doctor wording and watching it fail.
CodeQL reported two `py/stack-trace-exposure` alerts (medium). Both are real,
though for different reasons.

`/readyz` is unauthenticated and returned `str(exc)` from whatever the sqlite3
probe raised. A sqlite3 message carries the database path and often schema
detail, handed to anyone who can reach the port. A readiness probe needs one
bit; the detail goes to the server's own log, where an operator can already
see it.

The job-enqueue handler returned `str(exc)` from `QueueFull`, whose message
this codebase writes itself, so nothing untrusted was leaking today. The habit
is still the thing worth removing: the next exception to reach that handler may
not be one we wrote. It now returns a fixed message plus `max_active_jobs` as
a field, which is also easier for a client to act on than parsing prose.

tests/integration/test_selfhosted_server.py gains a test that makes `/readyz`
fail with a message containing a database path and asserts the response body
contains neither it nor the error text.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

The Windows leg added in #53 turned up a second latent problem, alongside the
retention bug: `scripts/e2e.py` failed the build on any non-zero exit from
`apiverity regression`.

EXIT_FINDINGS means "a regression was detected" -- the command working exactly
as documented. And on a contended runner a mock server on localhost genuinely
does go from 1.7ms to 16ms, past even the 400% tolerance that was chosen to be
generous. The step's own comment already said its job was to "verify the
command wiring and exit codes end-to-end"; it then gated on the one thing that
depends on how loaded the machine is.

That is the failure mode where a red build teaches people to ignore red builds.
The step now accepts EXIT_OK or EXIT_FINDINGS and fails only on a usage,
unreachable or internal code -- which is what "the wiring works" actually
means. The comparison logic keeps its unit tests.

Worth noting what the tool did right while failing this: it separated three
genuine threshold breaches from four it reported as inconclusive, with the
overlapping intervals printed and a suggestion to raise --iterations. The
statistics were not the problem.

Also formats the test added in the previous commit; CI checks `tests` too and I
had only re-run ruff over `apiverity`.
CI's Format check covers tests as well as apiverity; the cherry-pick carried
the code change but I re-ran the formatter before it, not after.
@webdevsamran
webdevsamran merged commit c249c71 into main Sep 7, 2026
12 checks passed
@webdevsamran
webdevsamran deleted the fix/stack-trace-exposure branch September 7, 2026 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant