Skip to content

Security: clear the open Dependabot and CodeQL alerts - #75

Merged
igorbenav merged 4 commits into
mainfrom
fix/security-alerts
Jun 7, 2026
Merged

igorbenav merged 4 commits into
mainfrom
fix/security-alerts

Conversation

@igorbenav

Copy link
Copy Markdown
Collaborator

Security: clear the open Dependabot and CodeQL alerts

This branch closes the standing security alerts against the repository — the Dependabot advisories on locked dependencies and the CodeQL findings in the source. It removes a dependency that was never used (and dragged in unfixable transitive vulnerabilities), refreshes the genuinely vulnerable packages to patched releases, stops error responses from echoing raw exception text, swaps an MD5 cache-key hash for SHA-256, and locks the CI workflows down to read-only token scope. No runtime API changes; the dependency-constraint changes are minimal and called out below.


Vulnerable dependencies patched

The lock file carried a stack of advisories — high-severity ones in urllib3 (decompression bombs, redirect header leakage), python-multipart (arbitrary file write and DoS), aiomysql (arbitrary client file access), and starlette (Range-header DoS and Host-header path poisoning), plus a long tail of moderate/low issues in idna, python-dotenv, filelock, requests, virtualenv, pygments, pymdown-extensions, and pytest.

The fix is a surgical lock refresh: each flagged package was upgraded to its patched release and nothing else was touched. python-multipart → 0.0.32, urllib3 → 2.7.0, aiomysql → 0.3.2, starlette → 1.2.1, idna → 3.18, python-dotenv → 1.2.2, filelock → 3.29.1, requests → 2.34.2, virtualenv → 21.4.2, pygments → 2.20.0, pymdown-extensions → 10.21.3, pytest → 9.0.3. fastapi moved 0.118 → 0.136 as well — not because it was flagged, but because the patched Starlette requires a newer FastAPI, so the bump is a dependency of the Starlette fix rather than an independent upgrade.

Why: Keeping pydantic, sqlalchemy, uvicorn, and the rest pinned at their previous locked versions keeps the security PR reviewable — the only versions that move are the ones a CVE forced. The full test suite passes against the bumped fastapi/starlette, so the cascade is validated rather than assumed.


python-jose removed entirely

python-jose was a declared runtime dependency, but nothing in the codebase imports it — the admin uses signed cookie sessions, not JWTs. It was pulling in ecdsa, pyasn1, and rsa transitively, and those accounted for four alerts on their own, including the ecdsa Minerva timing attack on P-256 — which has no fixed release, because the maintainers treat the side channel as a documented limitation rather than a bug.

Dropping python-jose removes all four of those alerts at once and can't be solved any other way, since no version bump clears the Minerva finding.

Why: A version bump was impossible for the unfixable ecdsa issue, and the dependency earned its keep nowhere — so removing it is both the only fix and a net reduction in attack surface.


Error responses no longer leak exception details

Several admin error paths returned the raw exception text to the client — bulk-delete failures, the create/update request handlers, and the relationship data/options endpoints all built responses like {"message": f"Error loading related data: {str(e)}"}. CodeQL flagged these as information exposure: a stack-deep str(e) can surface table names, SQL fragments, or internal paths to whoever triggers the error.

Each of those handlers now logs the exception server-side (via the module logger, where it's useful for debugging) and returns a fixed, generic message to the client — "Error during deletion.", "Error loading related data.", and so on. The form-rendering paths, which deliberately show validation feedback to the user, are unchanged.


SHA-256 instead of MD5 for memcached keys

The Memcached backend hashes overly long cache keys to stay under Memcached's 250-byte key limit, and it used MD5 to do it. The hash isn't protecting anything — it's a key-shortening device, not a security primitive — but CodeQL flags any MD5 over data as a broken-hash finding, and there's no reason to keep a weak algorithm here.

Both the backend and the test helper that mirrors its key encoding now use SHA-256, with the truncation budget adjusted (key[:150] plus the 64-char digest) so the composed key still fits comfortably under the limit.


CI workflows locked to read-only

The linting, tests, and type-check workflows declared no permissions block, so they ran with the repository's default — often broader than a test job needs. Each now declares permissions: contents: read at the top, matching the pattern already used across the sibling projects, so the GITHUB_TOKEN in these jobs can do nothing but check out code.


Test Plan

Automated

  • uv run pytest — 345 passed (SQLite; Postgres/MySQL container paths run in CI)
  • uv run ruff check / ruff format --check / uv run mypy crudadmin — all clean
  • App startup + endpoint behavior exercised by the TestClient suite against the bumped fastapi 0.136 / starlette 1.2.1

Dependencies

  • python-jose, ecdsa, pyasn1, rsa no longer present in uv.lock
  • Every flagged package resolves to a patched version in uv.lock
  • No imports of jose/jwt remain anywhere in crudadmin or tests

Error responses

  • Bulk-delete, create/update, and relationship endpoints return generic messages; details are logged, not returned

Hashing

  • Memcached session/cache tests pass with the SHA-256 key encoding (backend and test helper kept in sync)

Workflows

  • All three workflow files declare permissions: contents: read

Dependencies

  • Removed: python-jose (unused; eliminated the ecdsa/pyasn1/rsa transitive chain).
  • Constraint raised: aiomysql (mysql extra) >=0.2.0 → >=0.3.0 for CVE-2025-62611.
  • All other changes are lock-file version bumps within the existing pyproject constraints; no new dependencies were added.

Breaking Changes

  • python-jose is no longer installed by CRUDAdmin. It was unused, but any downstream code that relied on importing jose transitively through this package — rather than declaring it directly — will fail to import. The fix on their side is to declare python-jose as their own dependency.
  • aiomysql>=0.3.0 is now required for the mysql extra. Anyone pinned to aiomysql 0.2.x must upgrade; 0.3.0 changed how LOAD DATA LOCAL INFILE is configured, which only matters if you use that in your own code.
  • Admin error responses are now generic. The JSON error bodies from bulk-delete and the relationship endpoints no longer include the underlying exception text. Any client or test asserting on the specific error string will need to stop doing so — the detail now lives in the server logs.

@igorbenav
igorbenav merged commit 70e94ed into main Jun 7, 2026
15 checks passed
@igorbenav
igorbenav deleted the fix/security-alerts branch June 7, 2026 03:33
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