Skip to content

TT3: credential sent through urllib.request.build_opener(...).open() is not reported #714

Closed

Description

@jamesjsanders

Checked on v2.12.0 and main at 3527006, --no-llm.

behavioral_taint_tracking._NETWORK_OUTPUT_SINKS includes urllib.request.urlopen but not OpenerDirector.open. This is reported as TT3:

req = urllib.request.Request(URL, headers={"Authorization": "Bearer " + os.environ["API_KEY"]})
urllib.request.urlopen(req)

The same request sent through an opener is not:

urllib.request.build_opener().open(req)

So a common hardening step (an opener with a no-redirect handler, so the Authorization header cannot follow a redirect to another origin) silences the finding, and any skill can send an environment credential out this way without TT3 firing.

Activity

  1. agentsope commented on Oct 4, 2026

    @agentsope
    Contributor

    I've opened #721 with a deliberately scoped, partial improvement: recognize directly chained build_opener(...).open(...) calls (including absolute import aliases and handler arguments), with conservative binding checks and regression tests. The behavioral taint module passes all 106 tests; the offline non-integration/non-provider suite passes 8,533 tests.

    One separate gap surfaced during analyzer-level reproduction: nesting os.environ["API_KEY"] inside Request headers misses TT3 even for the direct urlopen(req) control on the tested main commit. With .get("API_KEY"), the control reports TT3 and #721 restores the inline opener finding. That nested-subscript propagation gap and opener instances first stored in variables remain outside this PR, so this issue should stay open. Happy to discuss whether this small step is useful before extending the scope.

  2. rng1995 commented on Oct 4, 2026

    @rng1995
    Collaborator

    Merge-state update checked on 2026-10-19: merged PR #721 covers both directly chained and stored urllib opener instances. The remaining nested-header source-propagation gap now has an open implementation in PR #826.

    Keeping this issue open. On current main 95a52d89, after merged PR #799, the original nested os.environ["API_KEY"] inside Request(..., headers=...) still misses TT3 through direct urlopen, inline opener, and stored opener forms. Corresponding .get() controls report TT3; public-payload controls do not.

    Fresh offline behavioral-taint, SC8, and command-wrapper verification passed 349 tests, alongside the direct source-gap reproductions. No sample network requests or live provider calls were executed. #826 has not merged.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions