Skip to content

Azure python sanitizer upstream2#21288

Merged
tausbn merged 23 commits intogithub:mainfrom
microsoft:azure_python_sanitizer_upstream2
Feb 18, 2026
Merged

Azure python sanitizer upstream2#21288
tausbn merged 23 commits intogithub:mainfrom
microsoft:azure_python_sanitizer_upstream2

Conversation

@bdrodes
Copy link
Contributor

@bdrodes bdrodes commented Feb 6, 2026

  • Clean up of test cases to use postprocessing
  • Adding full ssrf path sanitization for the new AntiSSRF python API.

bdrodes and others added 11 commits February 6, 2026 11:18
…orgery/test_azure_client.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…orgery/test_azure_client.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…caes to use postprocessing results. Currently results for partial ssrf still need work, it is flagging cases where the URL is fully controlled, but is sanitized. I'm not sure if this should be flagged yet.
@github-actions github-actions bot added the Python label Feb 6, 2026
@bdrodes bdrodes marked this pull request as ready for review February 9, 2026 18:23
@bdrodes bdrodes requested a review from a team as a code owner February 9, 2026 18:23
Copilot AI review requested due to automatic review settings February 9, 2026 18:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Python SSRF (CWE-918) query tests to use inline-expectations postprocessing and adds modeling/tests for the AntiSSRF library’s URI validation as a sanitizer for full URL control.

Changes:

  • Migrate SSRF query-tests to utils/test/InlineExpectationsTestQuery.ql postprocessing.
  • Expand SSRF test coverage for requests, http.client, Azure SDK sinks, and new AntiSSRF validation APIs.
  • Add an AntiSSRF URIValidator barrier/sanitizer to SSRF dataflow customizations and record the change in change notes.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_requests.py Adds more requests SSRF cases and AntiSSRFPolicy-based safe/unsafe session scenarios with inline expectations.
python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py New tests covering AntiSSRF URIValidator domain checks and how they interact with SSRF sink classification.
python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_http_client.py Updates http.client SSRF tests to inline expectations and adds sink annotations.
python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py Converts Azure SSRF sink tests to inline expectations and simplifies call formatting.
python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/full_partial_test.py Refactors existing full/partial SSRF test cases to inline expectations and adds explicit alert annotations.
python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.qlref Switches to query:/postprocess: format to enable inline expectations postprocessing.
python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/PartialServerSideRequestForgery.expected Regenerated expected output for postprocessed partial SSRF tests.
python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/FullServerSideRequestForgery.qlref Switches to query:/postprocess: format to enable inline expectations postprocessing.
python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/FullServerSideRequestForgery.expected Regenerated expected output for postprocessed full SSRF tests.
python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll Adds AntiSSRF URIValidator barrier/guard modeling for full URL control sanitization.
python/ql/lib/change-notes/2026-02-09-ssrf_test_case_cleanup_and_new_ssrf_barriers.md Documents the SSRF test cleanup and new AntiSSRF barrier behavior.
Comments suppressed due to low confidence (47)

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:21

  • Variable c is not used.
        c = SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:35

  • Variable c is not used.
        c = KeyClient(vault_url=full_url, credential=credential)  # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:37

  • Variable c is not used.
        c = KeyClient(vault_url=full_url, credential=credential)  # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:51

  • Variable c is not used.
        c = ShareFileClient.from_file_url(full_url) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:53

  • Variable c is not used.
        c = ShareFileClient.from_file_url(full_url) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:130

  • Variable c is not used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:132

  • Variable c is not used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_requests.py:29

  • Variable response is not used.
    response = session.get(user_input)

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_requests.py:39

  • Variable response is not used.
    response = session.get(user_input) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_requests.py:49

  • Variable response is not used.
    response = session.get(user_input) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py:16

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    c = SecretClient(vault_url=full_url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py:17

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    c = ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py:18

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    c = ShareFileClient.from_file_url(full_url) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py:19

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    c = KeyClient(url, credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py:20

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    c = KeyClient(full_url, credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_azure_client.py:21

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    c = ContainerClient.from_container_url(container_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:16

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:30

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = KeyClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:32

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = KeyClient(vault_url=url, credential=credential)  # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:46

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:48

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = ShareFileClient.from_file_url(url) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:64

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:66

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:69

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:71

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:74

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:76

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:79

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:81

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:85

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:87

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:90

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:92

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:95

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:97

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:100

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:102

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:105

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:107

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:110

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:112

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:115

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:117

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:120

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:122

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:125

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/full-ssrf]

python/ql/test/query-tests/Security/CWE-918-ServerSideRequestForgery/test_path_validation.py:127

  • This assignment to 'c' is unnecessary as it is redefined before this value is used.
    This assignment to 'c' is unnecessary as it is redefined before this value is used.
        c = SecretClient(vault_url=url, credential=credential) # $ Alert[py/partial-ssrf]

Copy link
Contributor

@owen-mc owen-mc left a comment

Choose a reason for hiding this comment

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

I haven't finished looking at this yet.

@owen-mc
Copy link
Contributor

owen-mc commented Feb 12, 2026

I finished reviewing. The tests cover all the new sanitizers, which is good. My only remaining issue is around whether the sanitizer guard definition needs all the logic around different kinds of comparisons.

Copy link
Contributor

@owen-mc owen-mc left a comment

Choose a reason for hiding this comment

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

Thanks for fixing that.

@owen-mc owen-mc dismissed their stale review February 12, 2026 14:01

Changes made

Copy link
Contributor

@tausbn tausbn left a comment

Choose a reason for hiding this comment

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

A few suggestions, otherwise this looks good to me. 👍

@yoff
Copy link
Contributor

yoff commented Feb 12, 2026

My only remaining issue is around whether the sanitizer guard definition needs all the logic around different kinds of comparisons.

My hope was that #21296 could alleviate that, if we merge that first and rebase. However, doing it the other way round would also be fine. Then that PR could be made to simplify the logic of this one..

…tForgeryCustomizations.qll

Co-authored-by: Taus <tausbn@github.com>
…nd_new_ssrf_barriers.md

Co-authored-by: Owen Mansel-Chan <62447351+owen-mc@users.noreply.github.com>
Copy link
Contributor

@tausbn tausbn left a comment

Choose a reason for hiding this comment

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

Looks good to me. Merging.

@tausbn tausbn merged commit 6b6d886 into github:main Feb 18, 2026
22 checks passed
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.

4 participants

Comments