Skip to content

Cross-File Security Scanning

Time: 15 minutes | Tools: cross_file_security_scan | Tier: Pro

Learn to detect vulnerabilities where tainted data flows across file boundaries.

What You'll Learn

  • Why single-file scanning misses vulnerabilities
  • How cross-file taint tracking works
  • Interpreting cross-file results
  • Prioritizing fixes

The Problem

Single-file scanning misses this vulnerability:

# routes/auth.py
@app.route('/login', methods=['POST'])
def login():
    username = request.form['username']  # Taint source
    user = user_service.get_user(username)  # Passes taint
    return render_template('profile.html', user=user)
# services/user_service.py
def get_user(username):
    return db_service.query_user(username)  # Passes taint
# services/db_service.py
def query_user(username):
    query = f"SELECT * FROM users WHERE name = '{username}'"  # SINK!
    return cursor.execute(query)

The taint flows across three files. Single-file scans see nothing wrong in any individual file!

Step 1: Run Cross-File Scan

"Scan the entire project for security vulnerabilities that span multiple files"

{
  "tool": "cross_file_security_scan",
  "parameters": {
    "project_root": "./flask_app",
    "max_depth": 5,
    "include_diagram": true
  }
}

Step 2: Understand the Results

{
  "data": {
    "vulnerabilities": [
      {
        "type": "SQL_INJECTION",
        "severity": "CRITICAL",
        "cwe": "CWE-89",
        "confidence": 0.95,
        "taint_flow": {
          "source": {
            "file": "routes/auth.py",
            "line": 5,
            "expression": "request.form['username']"
          },
          "path": [
            {
              "file": "routes/auth.py",
              "line": 6,
              "call": "user_service.get_user(username)"
            },
            {
              "file": "services/user_service.py",
              "line": 8,
              "call": "db_service.query_user(username)"
            }
          ],
          "sink": {
            "file": "services/db_service.py",
            "line": 12,
            "expression": "cursor.execute(query)"
          }
        },
        "files_involved": [
          "routes/auth.py",
          "services/user_service.py",
          "services/db_service.py"
        ]
      }
    ],
    "taint_diagram": "graph TD\n  A[request.form - auth.py:5] --> B[get_user - user_service.py:8]\n  B --> C[query_user - db_service.py:12]\n  C --> D[cursor.execute - SINK!]",
    "risk_assessment": {
      "total_vulnerabilities": 1,
      "critical": 1,
      "high": 0,
      "cross_file_vulns": 1,
      "files_at_risk": 3
    }
  },
  "tier_applied": "pro",
  "duration_ms": 456
}

Step 3: Visualize the Flow

The scan generates a taint flow diagram:

graph TD
    A["request.form['username']<br/>routes/auth.py:5"] --> B["get_user(username)<br/>user_service.py:8"]
    B --> C["query_user(username)<br/>db_service.py:12"]
    C --> D["cursor.execute(query)<br/>⚠️ SQL INJECTION"]

    style A fill:#ffcccc
    style D fill:#ff6666

Step 4: Understand the Risk

Why This Is Critical

  1. Attack vector: User-controlled input from a web form
  2. No sanitization: Data passes through unchanged
  3. Dangerous sink: Direct SQL execution
  4. Impact: Full database access, data theft, data manipulation

Attack Example

Username input: ' OR '1'='1' --

Becomes:

SELECT * FROM users WHERE name = '' OR '1'='1' --'

Returns all users!

Step 5: Fix the Vulnerability

# services/db_service.py
def query_user(username):
    query = "SELECT * FROM users WHERE name = ?"
    return cursor.execute(query, (username,))  # Parameterized

Option 2: Fix at the Source

# routes/auth.py
from utils.validators import sanitize_username

@app.route('/login', methods=['POST'])
def login():
    username = sanitize_username(request.form['username'])
    user = user_service.get_user(username)
    return render_template('profile.html', user=user)

Option 3: Defense in Depth (Best)

Both! Sanitize at entry, parameterize at database.

Step 6: Verify the Fix

"Rescan the project for cross-file vulnerabilities"

After fixing:

{
  "data": {
    "vulnerabilities": [],
    "risk_assessment": {
      "total_vulnerabilities": 0,
      "critical": 0,
      "cross_file_vulns": 0
    }
  }
}

Common Cross-File Patterns

Pattern 1: Request → Service → Database

routes/*.py → services/*.py → db_service.py

Risk: SQL Injection, NoSQL Injection

Pattern 2: Request → Template

routes/*.py → templates/*.html

Risk: XSS (Cross-Site Scripting)

Pattern 3: Request → Shell

routes/*.py → utils/*.py → os.system()

Risk: Command Injection

Pattern 4: Request → File System

routes/*.py → services/*.py → open()

Risk: Path Traversal

Scan Configuration

Adjust Depth

{
  "tool": "cross_file_security_scan",
  "parameters": {
    "project_root": ".",
    "max_depth": 10  // Follow more call levels
  }
}

Specify Entry Points

{
  "tool": "cross_file_security_scan",
  "parameters": {
    "project_root": ".",
    "entry_points": ["routes/auth.py:login", "routes/api.py:handle_request"]
  }
}

Confidence Threshold

{
  "tool": "cross_file_security_scan",
  "parameters": {
    "project_root": ".",
    "confidence_threshold": 0.8  // Only high-confidence findings
  }
}

Try It Yourself

Exercise 1: Scan Your Project

"Run a cross-file security scan on my project"

Exercise 2: Focus on Entry Points

"Scan for vulnerabilities starting from the API routes"

Exercise 3: Generate a Security Report

"Create a security report for this codebase"

Tier Requirements

Feature Community Pro
Single-file scan
Cross-file scan
Taint diagrams
Entry point focus
Custom thresholds

Key Takeaways

  1. Single-file scans miss cross-file vulnerabilities
  2. Taint flows through function calls across modules
  3. Visualize flows with the generated diagrams
  4. Fix at the sink (parameterized queries) is most reliable
  5. Defense in depth is best (sanitize AND parameterize)

Next Tutorial

Expand this workflow with the DevOps Guide to turn security scans into CI/CD gates.