Skip to content

fix: resolve 15 CodeQL alerts and a proxy sample-count wrap - #29

Merged
Evil0ctal merged 4 commits into
mainfrom
fix/code-scanning-alerts
Oct 1, 2026
Merged

Evil0ctal merged 4 commits into
mainfrom
fix/code-scanning-alerts

Conversation

@Evil0ctal

Copy link
Copy Markdown
Member

What and why

CodeQL had 16 open alerts on main. None of them is exploitable. The release images are linux/amd64 and linux/arm64 only, where int is 64 bits. Every flagged value is either already bounded or written by this service's own Lua scripts. Triaging them still turned up one real bug on one of the same data flows. Fixing the other alerts costs only a few lines each, which is better than 15 dismissals.

The bug. A proxy's per-site sample count (sn) grows by one per observation and is never capped, but proxyapi carries it as an int32. Past 2^31−1 observations, ListProxies and GetProxy return a negative or tiny number: 4294967297 comes out as 1. CodeQL flagged the int(int64) in proxy/hot.go but not the int32(s.Samples) at proxyapi/convert.go:50, which is where the wrap actually happens. Its flow stops at the first conversion it reports.

Alerts Where Change
#4–#9 hotstate/reader.go, proxy/hot.go Saturate the hot-state counters with clampInt32 where they are read back from Valkey. This fixes the wrap above.
#3 api/secretapi/secrets.go Replace min(v, math.MaxInt32) with the package's clampInt32. CodeQL does not model min.
#10, #11 proxy/importparse.go Parse max_concurrency with bit size 32. A value outside the int32 range now fails while parsing, with the range check's own message.
#12–#16 scheduler/args.go, scheduler/reap.go Add an atoi helper that parses Lua reply fields with bit size 32. On a 32-bit build it saturates instead of wrapping.
#1 examples/fastapi-crawler/app/main.py Answer a fixed reason instead of str(err). The exception class still goes to the log.

This PR does not change #2 (js/insecure-randomness in web/e2e/access.spec.ts). There, Math.random() only makes e2e resource names unique; CodeQL flags it because the variable is called username. The plan is to dismiss it as "Used in tests".

How it was verified

  • go build ./... passes on darwin/arm64 and with GOOS=linux GOARCH=386. go vet passes on the four packages on both. golangci-lint v2.13.2 reports 0 issues across the module (--build-tags e2e).
  • go test -short -race passes on secretapi, proxy, hotstate and scheduler. The container-backed TestIdentityHotState and TestListProxiesHotState (PostgreSQL + Valkey) also pass.
  • The regression tests fail on main. The new hotstate and proxy subtests get 4294967297 instead of 2147483647, and TestParseLines gets an extra parsed row for line 9.
  • I ran CodeQL 2.27.1 locally with the same suites as default setup. On main it reproduces the 14 Go alerts at GitHub's locations. This branch reports 0 Go and 0 Python results, with nothing new.
  • examples/fastapi-crawler: pytest gives 15 passed and 3 skipped (the integration tests need EXAMPLE_URL).

Checklist

  • Comments and identifiers are English
  • No brand or platform names in code, tests, examples or documentation
  • Tests cover the new behaviour, or a regression test reproduces the fixed bug
  • documents/en/ and documents/zh/ both updated, and they say the same thing: not needed, since they only quote crawler.py, which is unchanged
  • CHANGELOG.md updated if a user can see the change
  • Generated code was regenerated with make generate, not edited by hand: no generated code touched

A proxy's per-site sample count (sn) grows by one per observation and is
never capped, but proxyapi carries it as an int32: past 2^31-1 observations
ListProxies/GetProxy returned a negative or tiny number (4294967297 came out
as 1). CodeQL flagged the int(int64) at proxy/hot.go but not the int32()
at proxyapi/convert.go where the wrap actually happens, because its flow
stops at the first conversion it reports.

Saturate where the counters are read back from Valkey, with the clampInt32
the snapshot writer already uses: the proxy site counters in proxy/hot.go
and the identity counters in hotstate/reader.go (global samples, active
leases, per-group samples and failure streak). The identity API already
clamped its own copies, so for it this only makes 32-bit builds correct.

Resolves code-scanning alerts #4-#9 (go/incorrect-integer-conversion).
Neither conversion could wrap, but CodeQL could not see the bound.

- A proxy import's max_concurrency was parsed with Atoi and only range
  checked later, by Attributes.validate. Parsing it with bit size 32 makes
  the later int32 conversions provably lossless; a value outside the int32
  range now fails while parsing, with the same message the range check
  gives.
- ListSecretAccessLogs bounded the version with min(), which CodeQL does
  not model. It now uses the package's clampInt32.

Resolves code-scanning alerts #3, #10 and #11 (go/incorrect-integer-conversion).
parseAcquire and reapBatch narrowed int64 reply fields to int: the lease
count, payload and type versions, the rebind counter and the reaper's
batch count. Every one fits in 32 bits by construction, so nothing wraps on
the 64-bit images, but on a 32-bit build a value like 4294967297 would
become 1 and, for the lease count, pass the reply-length check. A small
atoi helper parses with bit size 32, which saturates instead of wrapping.

Resolves code-scanning alerts #12-#16 (go/incorrect-integer-conversion).
The FastAPI example returned str(UpstreamError) to its HTTP caller. That
text is only "request to the target failed: <httpx class>", so no message
or traceback leaked, but it is exception data on an unauthenticated
endpoint of code people copy. The reason is now the fixed text; the class
still goes to the log, and Spinneret already gets the error_kind with the
report.

Resolves code-scanning alert #1 (py/stack-trace-exposure).
@Evil0ctal
Evil0ctal merged commit d0ccc11 into main Oct 1, 2026
11 checks passed
@Evil0ctal
Evil0ctal deleted the fix/code-scanning-alerts branch October 1, 2026 23:46
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