Skip to content

Hosted Maven splices the API's suffixed version into pom.xml unchecked, while hosted Gradle refuses the same grant #882

Description

[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: discussion #560 register.

Kind: bug. Source: new finding (register E63); related to review Part 5.4 (JVM) and E40.

Problem

Both hosted JVM planners take the pinned version from the same API field, RegistryOverrideIdentifiers::maven_suffixed_version, but only the Gradle one checks it. Verified on 9c43dfc:

  • Hosted Gradle puts the grant in a HostedRow and refuses it with redirect_gradle_override_invalid unless HostedRow::valid holds. That check requires safe coordinates, a canonical lowercase uuid, suffixed == <base>-socket.<uuid[..8]>, an https URL and two lowercase sha256s (plan_dep).``
  • Hosted Maven (rewrite_maven_pom) clones the string and splices it verbatim into every matching <version>. The same string also goes into the .mvn/checksums path. There is no grammar check and no XML escaping. Its unit fixture already pins a suffix that Gradle would refuse: patch_uuid: "uuid" with 1.7.36-socket.aaaaaaaa.

The <base>-socket.<hex8> grammar now has four builders and no shared validator:

The group/artifact derivation is also written twice: inline in rewrite_maven_pom and as gradle::coords_of.``

Proof by execution (a throwaway unit test, run twice on 9c43dfc). One DepOverride per suffix, with a canonical uuid 4d5e6f70-…, was run through rewrite_registry_redirect once against a Gradle build and once against a one-dependency pom.xml:

maven_suffixed_version hosted Gradle hosted Maven
1.10.0-socket.4d5e6f70 confirmed pinned
1.10.0-socket.DEADBEEF refused redirect_gradle_override_invalid pinned, no warning
1.10.0-socket.4D5E6F70 refused pinned, no warning
1.10.0-patched refused pinned, no warning
1.10.0</version><scope>system</scope><version>1.10.0 refused spliced into pom.xml as markup, no warning

Symptoms and impact

  • In a mixed Maven + Gradle repository, the same grant is refused for one build and silently pinned for the other.
  • If the pinned suffix is not <base>-socket.<hex8 of uuid>, VEX's consumed-copy lookup (which rebuilds the suffix from the uuid) and vendored mode look for a different version directory than the one hosted Maven pinned. I read this path but did not execute it.
  • The patch server is trusted, so this is defense in depth and drift, not an exploit. But the Maven writer is the only hosted writer that splices server text into markup without validating it. Size: small, about 1 function plus a shared helper.

Proposed change

  • Add one JVM grant reader beside formats::maven::split_socket_version. It provides suffixed_version(base, uuid), is_suffix_of(base, uuid, s) and maven_grant(dep) -> Result<MavenGrant, Refusal>, which covers coordinates, suffix, uuid and sha256s.
  • HostedRow::valid and rewrite_maven_pom both use it. Hosted Maven refuses an invalid grant with a warning code, as Gradle does, instead of pinning it.
  • Delete redirect::gradle::suffixed_version, coords_of and the inline coordinate derivation in rewrite_maven_pom. Have jvm::Coords::suffixed_version delegate to the shared builder.
  • Out of scope: the CLI vex_consumed copy, which is child 3 of Tracking: move vex_consumed's per-ecosystem consumed-copy rules from the CLI into core #855 and should call the same builder once it lands.

Size and scope

Acceptance criteria

  • Hosted Maven refuses a grant whose suffix isn't <base>-socket.<uuid[..8]>, whose uuid isn't canonical, or whose coordinates aren't safe, and writes nothing for that dep.
  • Regression test: the five suffixes above give the same accept/refuse verdict for Maven and Gradle.
  • The Maven unit fixtures use a canonical uuid and a matching suffix.
  • One suffix builder remains in core. jvm::Coords, hosted Gradle and the new validator share it.
  • cargo test -p socket-patch-core --lib redirect, plus the hosted Maven and Gradle e2e suites, stay green.

Dependencies

None. This unblocks the Maven child of #855 (one builder to call) and makes #717's pom-locating work independent of grant validation.

Activity

  1. added
    bugSomething isn't working
    arch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)
    on Oct 5, 2026
  2. mikolalysenko commented on Oct 7, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Re-checked on main 05ecc6e. The code moved, and the defect is unchanged.

    • Hosted Maven reads the grant at mod.rs#L6817 and splices it verbatim into <version>. It also uses it for the .mvn/checksums paths (L7087-L7091). Nothing between the read and the splice checks the <base>-socket.<hex8> grammar.
    • Hosted Gradle still gates the same field with HostedRow::valid.

    No open PR claims this issue. #1032 (one vendor::jvm::layout) is the natural home for a shared suffix validator.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 8, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Re-checked against main @ cf8b164 (architecture audit, ecosystems and formats). #1032 moved the JVM layout into vendor::jvm::layout, but this defect is unchanged.

    • Hosted Maven still clones the API string and splices it as is: redirect/mod.rs#L6802 and #L6967. There is still no grammar check.
    • Hosted Gradle still refuses an invalid row through HostedRow::valid,`` which now takes its coordinate check from jvm::layout::safe_coordinates.
    • The suffix builders are still separate copies:
      • jvm::Coords::suffixed_version/hex8 strips dashes and lowercases. formats::sbt::owned_file::suffixed_version delegates to it, so it is not a new copy.
      • gradle::suffixed_version uses uuid.get(..8).
      • The CLI copy is in vex_consumed.rs#L587-L590.``

    No open PR touches rewrite_maven_pom's suffix handling. PR #1036 (E26, one Maven backend) edits the vendored side only.


    Generated by Claude Code

  4. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    v5 triage: P3, not a release blocker. Validation of a malformed server-supplied Maven version is defensive hardening, outside the single-instance valid-input release gate. Retain P3.

    This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.

  5. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Re-checked on main @ 9ab72d4 by the architecture audit (ecosystems and formats). The finding still holds; the code has moved.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)bugSomething isn't workingpm:mavenMavenpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions