Skip to content

Python: Add jump steps for global variable nested field access #20162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

Napalys
Copy link
Contributor

@Napalys Napalys commented Aug 4, 2025

Adds globalVariableNestedFieldJumpStep to track data flow through nested attribute access on global variables (e.g., app.obj.foo). Supports tracking writes and reads on the same global variable attribute paths up to a configurable depth limit.

@github-actions github-actions bot added the Python label Aug 4, 2025
@Napalys Napalys force-pushed the python/global_variable_tracking branch from e870ee4 to 485f397 Compare August 10, 2025 16:07
@Napalys Napalys marked this pull request as ready for review August 11, 2025 09:36
@Napalys Napalys requested a review from a team as a code owner August 11, 2025 09:36
@Copilot Copilot AI review requested due to automatic review settings August 11, 2025 09:36
Copy link
Contributor

@Copilot 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 adds jump steps for global variable nested field access in Python dataflow analysis to track data flow through nested attribute access on global variables (e.g., app.obj.foo). The changes update test expectations and add core functionality to support tracking writes and reads on the same global variable attribute paths up to a configurable depth limit.

Key Changes

  • Adds globalVariableNestedFieldJumpStep predicate with supporting logic to track nested attribute access through global variables
  • Updates test files to use new inline expectations format with $ Alert and $ Source annotations
  • Enhances test coverage with new FastAPI path injection test cases

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll Adds core global variable nested field jump step implementation with depth-limited tracking
python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll Extends AttrWrite and AttrRead classes with helper methods for object-attribute matching
python/ql/test/library-tests/dataflow/fieldflow/test_global.py Adds test case for global variable nested attribute flow and updates expectations
python/ql/test/library-tests/dataflow/fieldflow/test.py Updates test expectations to reflect improved global flow tracking
python/ql/test/query-tests/Security/CWE-022-PathInjection/*.py Updates test annotations from old format to inline expectations format
python/ql/test/query-tests/Security/CWE-022-PathInjection/fastapi_path_injection.py Adds comprehensive FastAPI path injection test scenarios

// Base case: Direct global variable access (depth 0)
depth = 0 and
// We use `globalVar` instead of `globalVar.getAWrite()` due to some weirdness with how
// attribute writes are handled in the global scope (see `GlobalAttributeAssignmentAsAttrWrite`).
Copy link
Preview

Copilot AI Aug 11, 2025

Choose a reason for hiding this comment

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

The comment mentions 'some weirdness' which is too vague. Consider explaining the specific technical reason why globalVar.getAWrite() cannot be used here, or reference the specific issue with GlobalAttributeAssignmentAsAttrWrite.

Suggested change
// attribute writes are handled in the global scope (see `GlobalAttributeAssignmentAsAttrWrite`).
// We use `globalVar` instead of `globalVar.getAWrite()` because global attribute assignments
// in the global scope are not always represented as `AttrWrite` nodes by the extractor.
// Specifically, `GlobalAttributeAssignmentAsAttrWrite` models some global attribute assignments
// differently, so `getAWrite()` does not reliably capture all such cases. This ensures that
// both direct global variable accesses and global attribute assignments are handled correctly.

Copilot uses AI. Check for mistakes.

* Maximum depth for global variable nested attribute access.
* Depth 1 = globalVar.foo, depth 2 = globalVar.foo.bar, depth 3 = globalVar.foo.bar.baz, etc.
*/
private int getMaxGlobalVariableDepth() { result = 2 }
Copy link
Preview

Copilot AI Aug 11, 2025

Choose a reason for hiding this comment

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

The maximum depth is hardcoded to 2. Consider making this configurable through a parameter or constant that can be easily adjusted without modifying the predicate, especially since the feature description mentions 'configurable depth limit'.

Suggested change
private int getMaxGlobalVariableDepth() { result = 2 }
* This value is configurable: change `maxGlobalVariableDepth` below to adjust the depth limit.
*/
private int maxGlobalVariableDepth = 2
private int getMaxGlobalVariableDepth() { result = maxGlobalVariableDepth }

Copilot uses AI. Check for mistakes.

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.

2 participants