Python projects are exposed through both custom code and third-party packages, so one control rarely covers the full risk. Code scanning finds insecure logic, while dependency scanning catches known vulnerabilities in requirements and lock files. Teams that rely on only one view can miss exploit paths that originate in libraries, transitive packages, or unsafe implementation choices.
Why This Matters for Security Teams
Python applications rarely fail in only one way. Custom logic can introduce injection flaws, insecure deserialization, weak authentication handling, and unsafe file operations, while dependencies can bring in known CVEs, malicious packages, or transitive risk that never appears in the application source itself. Security teams that treat “scan the code” as a complete answer tend to underestimate the attack surface created by package managers, lock files, and build pipelines.
The practical issue is coverage. code scanning is strongest at spotting patterns in the project’s own logic, but it does not reliably tell a team whether a pinned package is exploitable or whether a vulnerable transitive dependency has entered the tree. Dependency scanning, including SBOM-informed review, helps close that gap by identifying issues in requirements and resolved artifacts. For governance and prioritisation, the NIST Cybersecurity Framework 2.0 is useful because it frames both asset visibility and risk treatment as ongoing work, not a one-time checkpoint.
In practice, many security teams encounter serious exposure only after a library update or hidden package path has already been deployed, rather than through intentional design review.
How It Works in Practice
Good coverage comes from combining two different questions. Code scanning asks, “Is the application written in a dangerous way?” Dependency scanning asks, “Are we importing risky software, directly or indirectly?” In Python, that usually means scanning the source tree, then separately analysing OWASP-relevant implementation patterns, requirements.txt, pyproject.toml, lock files, wheel metadata, and the final resolved dependency graph. The second view matters because Python packaging is flexible, and flexibility increases the chance that the deployed set of packages differs from what was originally reviewed.
- Use code scanning early in the pull request flow to catch insecure patterns before merge.
- Use dependency scanning on every build to identify known vulnerabilities and license or provenance issues.
- Compare declared dependencies with resolved dependencies so transitive packages are not missed.
- Prioritise findings by exploitability, reachability, and whether the vulnerable path is actually imported.
- Track exceptions carefully when a vulnerable package cannot be replaced immediately.
For software supply chain integrity, guidance from NIST Secure Software Development Framework aligns well with this dual approach because it treats secure development, dependency control, and verification as part of the same lifecycle. Teams should also pay attention to build artefacts and container images, because a package may be clean in source control but altered or expanded later in CI/CD. These controls tend to break down when teams use ephemeral branches, unpinned dependencies, or multi-stage build pipelines that resolve packages at different points in the release process.
Common Variations and Edge Cases
Tighter dependency control often increases delivery overhead, requiring organisations to balance release speed against confidence in what is actually shipped. That tradeoff becomes more visible in Python ecosystems where teams use rapid prototyping, notebooks, or plugin-based architectures, because a strict allowlist can slow experimentation while a loose policy can hide risk.
Best practice is evolving on how aggressively to block builds for dependency findings. Current guidance suggests treating high-severity, reachable, and internet-exposed issues differently from dormant vulnerabilities that are not on an executable path. There is no universal standard for this yet, so organisations should define their own triage rules, especially for transitive dependencies where the team may not directly control the upstream maintainer.
Some edge cases deserve special handling: internally developed packages that are distributed like third-party libraries, optional extras that are only installed in certain environments, and monorepos where one scanner instance may not see every deployment target. Dependency scanning also needs human review when package names are similar to trusted libraries, because typosquatting and dependency confusion are supply chain concerns, not just versioning mistakes. In environments with fast-moving ML or agentic workloads, code and dependency scanning should be paired with runtime validation, because imported tooling can change behaviour after deployment.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
MITRE ATT&CK and OWASP Agentic AI Top 10 address the attack and risk surface, while NIST CSF 2.0 and NIST AI RMF set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| NIST CSF 2.0 | ID.RA-1 | Risk identification covers both insecure code and vulnerable packages. |
| MITRE ATT&CK | T1195 | Supply chain compromise maps to malicious or vulnerable dependency pathways. |
| OWASP Agentic AI Top 10 | Secure software pipelines for code and dependencies remain critical for AI-enabled apps. | |
| NIST AI RMF | GOVERN | AI governance principles apply when Python apps include models or AI-assisted code paths. |
Assign ownership for code and dependency risk wherever Python supports AI-enabled functionality.
Related resources from NHI Mgmt Group
- What is the difference between code scanning and runtime identity monitoring?
- What is the difference between scanning AI-generated code and governing AI agent identity?
- How should security teams prevent code injection in modern applications?
- When should teams move from code scanning to identity governance?