Skip to content

security: prepare v5.0.1 Django replay protection hotfix - #3871

Open
Jeff Stock (jstock03) wants to merge 1 commit into
microsoft:liamcrumm/esrp-ame-glibc235-publishfrom
jstock03:release/5.0.1-django-replay
Open

security: prepare v5.0.1 Django replay protection hotfix#3871
Jeff Stock (jstock03) wants to merge 1 commit into
microsoft:liamcrumm/esrp-ame-glibc235-publishfrom
jstock03:release/5.0.1-django-replay

Conversation

@jstock03

Copy link
Copy Markdown
Contributor

Summary

  • prepare the isolated v5.0.1 security patch from the exact public v5.0.0 source
  • backport the Django trust middleware replay protection reviewed and merged in fix: prevent replay attacks in Django trust middleware #3782
  • require request-bound signatures, timestamps, unique nonces, an explicit audience, and an atomic shared replay cache
  • synchronize non-exempt package manifests to 5.0.1 and add changelog, advisory, upgrade, and release documentation

Release topology

This PR targets liamcrumm/esrp-ame-glibc235-publish because that canonical branch points to the exact same commit as tag v5.0.0. This keeps the hotfix isolated from unrelated unreleased work on main. A maintainer can create a protected release/5.0 branch at v5.0.0 and retarget this PR before merge if preferred.

The implementation is already present on main through #3782. This PR prepares the independently reviewable patch-release tree and metadata.

Security behavior

The prior middleware authenticated only the agent DID, so an observed valid request could be replayed and unsigned request components could be changed. The fixed protocol binds the audience, timestamp, nonce, method, path and query, content type, and body digest into the Ed25519 signature. Verified nonces are claimed atomically and retained through the signature-validity window.

This is an intentional fail-closed compatibility change. DID-only signatures are rejected. Production servers must configure AGENTMESH_AUDIENCE and a shared Redis or memcached replay cache.

Validation

  • 44 focused Django middleware tests pass
  • changed-line coverage is 90% (129/143)
  • Ruff passes for all changed Python source and tests
  • repository version synchronization check passes
  • repository relative-link validation passes
  • agent_governance_toolkit_core-5.0.1-py3-none-any.whl builds successfully
  • the built wheel contains the patched middleware and reports version 5.0.1
  • all 44 replay tests pass against the installed wheel from site-packages

Publication gates

After approval:

  1. Run Publish Packages for agent-governance-toolkit-core with dry_run: true and inspect release-manifest.json, signatures, provenance, and the wheel contents.
  2. Publish the canonical core wheel through the approved ESRP path.
  3. Create the signed v5.0.1 tag and GitHub Release from the approved hotfix commit.
  4. Verify PyPI metadata, digest, installation, and GitHub attestation.
  5. Publish the coordinated GitHub Security Advisory and release announcement.

No internal incident identifiers or unassigned vulnerability identifiers are included in this PR.

Signed-off-by: Jeff Stock <jstock@microsoft.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I reviewed head f1a7a8e8 against target c57d9d9a, which is the v5.0.0 commit. I compared the security code with merged #3782, built and installed the core wheel in a clean environment, and ran all 44 Django middleware tests from the installed artifact. I also exercised request tampering and replay concurrency. Changes to the method, path, query, body, content type, timestamp, nonce, or signature returned 403. A reused nonce returned 403, and one of 32 concurrent copies passed. The replay defense behaves as intended.

The release artifact still has a blocking version mismatch:

METADATA:                 5.0.1
agentmesh.__version__:    5.0.0
agent_os.__version__:     5.0.0
agent_runtime.__version__: 5.0.0
hypervisor.__version__:   5.0.0

The four __init__.py files say their constants must stay in sync with package metadata, and the core wheel bundles all four namespaces. python scripts/sync-version.py --check reports success because the script does not inspect these constants. Please bump the four runtime versions to 5.0.1 and extend the version check or artifact test to cover them. A scanner or application that reads __version__ would classify the patched wheel as vulnerable 5.0.0 while importlib.metadata reports 5.0.1.

The changelog and release notes also state a release date of 2026-09-01. As of 2026-09-03, GitHub has no v5.0.1 tag or release and PyPI still serves 5.0.0. Please set the date at publication or use an unreleased placeholder until then.

After those release-integrity fixes, I have no security finding in the replay implementation.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The release topology is sound and I verified it rather than taking it on trust. There is one finding
that I think has to be resolved before this ships, and it is the kind that only shows up if you diff
the release tree against main rather than against the PR it backports.

Verified, all of it:

  • The base branch liamcrumm/esrp-ame-glibc235-publish points at c57d9d9a4849556a3c5347d359012d7a85bc3dfb, which is exactly what tag v5.0.0 resolves to. So "the exact public v5.0.0 source" is literally true, and building the patch off that branch really does isolate it from unreleased main work.
  • #3782 ("fix: prevent replay attacks in Django trust middleware") is merged, 2026-08-19.
  • Validate PR title shows red in the rollup but there is a SUCCESS 2 minutes 27 seconds later on the same head. That entry is stale, not a real failure.

The finding: this backports #3782 and stops there, but the same middleware was hardened again
afterwards.

#3813 ("fix: enforce signed http trust verification") merged to main on 2026-08-25, six days
after #3782 and a week before this PR was opened. It is tagged as a Security fix and it references a
published advisory, GHSA-5j58-vjjg-pcgm.

The diff shows the gap plainly. Against current main, this branch's middleware is behind:

middleware.py              47 added / 174 removed
request_auth.py            30 added /  12 removed
test_django_middleware.py  40 added / 100 removed

And the shared module #3813 introduced is absent entirely:

agent-governance-python/agent-mesh/src/agentmesh/integrations/request_auth.py
  main       -> present
  this PR    -> does not exist

which is why this branch's middleware.py drops the RequestTargetMode, decoded_target,
select_signed_headers and wsgi_raw_target imports, along with replay_key and
_VERIFIED_TRUST_SCORE.

So as it stands, v5.0.1 would ship a Django trust middleware that fixes the replay issue and does
not carry the fix for the advisory that followed it. Anyone who takes v5.0.1 because it is the
security patch release would be getting one of the two security fixes on that component, which is the
worst possible outcome for a release whose entire purpose is to be the safe thing to upgrade to.

What I would do. Backport #3813 onto this branch as well, and cover both in
docs/releases/RELEASE_NOTES_v5.0.1.md, the advisory text and the upgrade notes. If for some reason
#3813 is deliberately out of scope, that needs saying explicitly in the release notes, because a
patch release that silently omits a fix with a published GHSA is worse than no patch release.

The rest of the PR is in good shape. Preparing an isolated tree from the exact tag rather than
cherry-picking onto main is the right call, the fail-closed compatibility break is stated plainly
rather than buried, and offering the maintainers a protected release/5.0 branch at v5.0.0 as an
alternative target is the right way to raise a topology question you cannot resolve yourself.

One smaller note: this branch is 182 commits behind main, which is expected and correct given
it is deliberately cut at v5.0.0. Flagging it only so nobody reads the drift as staleness and
rebases it onto main, which would defeat the whole point.

@imran-siddique

Copy link
Copy Markdown
Collaborator

MohammadHaroonAbuomar liamcrumm this needs a maintainer decision before it ships, not just a
review.

The release topology checks out: the base branch points at exactly the v5.0.0 commit, and #3782 is
correctly backported. But the tree stops there, and #3813 ("fix: enforce signed http trust
verification") merged to main on 2026-08-25 with its own published advisory,
GHSA-5j58-vjjg-pcgm, hardening the same middleware.

So v5.0.1 as proposed would carry one of the two security fixes on that component. Anyone upgrading
because it is the security patch release gets the replay fix and not the advisory fix. Either
backport #3813 as well, or say explicitly in the release notes why it is out of scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants