By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts. View our Privacy Policy for more information.
ToolAccuracy of FindingsDetects Non-Pattern-Based Issues?Coverage of SAST FindingsSpeed of ScanningUsability & Dev Experience
DryRun SecurityVery high – caught multiple critical issues missed by othersYes – context-based analysis, logic flaws & SSRFBroad coverage of standard vulns, logic flaws, and extendableNear real-time PR feedback
Snyk CodeHigh on well-known patterns (SQLi, XSS), but misses other categoriesLimited – AI-based, focuses on recognized vulnerabilitiesGood coverage of standard vulns; may miss SSRF or advanced auth logic issuesFast, often near PR speedDecent GitHub integration, but rules are a black box
GitHub Advanced Security (CodeQL)Very high precision for known queries, low false positivesPartial – strong dataflow for known issues, needs custom queriesGood for SQLi and XSS but logic flaws require advanced CodeQL experience.Moderate to slow (GitHub Action based)Requires CodeQL expertise for custom logic
SemgrepMedium, but there is a good community for adding rulesPrimarily pattern-based with limited dataflowDecent coverage with the right rules, can still miss advanced logic or SSRFFast scansHas custom rules, but dev teams must maintain them
SonarQubeLow – misses serious issues in our testingLimited – mostly pattern-based, code quality orientedBasic coverage for standard vulns, many hotspots require manual reviewModerate, usually in CIDashboard-based approach, can pass “quality gate” despite real vulns
Vulnerability ClassSnyk (partial)GitHub (CodeQL) (partial)SemgrepSonarQubeDryRun Security
SQL Injection
*
Cross-Site Scripting (XSS)
SSRF
Auth Flaw / IDOR
User Enumeration
Hardcoded Token
ToolAccuracy of FindingsDetects Non-Pattern-Based Issues?Coverage of C# VulnerabilitiesScan SpeedDeveloper Experience
DryRun Security
Very high – caught all critical flaws missed by others
Yes – context-based analysis finds logic errors, auth flaws, etc.
Broad coverage of OWASP Top 10 vulns plus business logic issuesNear real-time (PR comment within seconds)Clear single PR comment with detailed insights; no config or custom scripts needed
Snyk CodeHigh on known patterns (SQLi, XSS), but misses logic/flow bugsLimited – focuses on recognizable vulnerability patterns
Good for standard vulns; may miss SSRF or auth logic issues 
Fast (integrates into PR checks)Decent GitHub integration, but rules are a black box (no easy customization)
GitHub Advanced Security (CodeQL)Low - missed everything except SQL InjectionMostly pattern-basedLow – only discovered SQL InjectionSlowest of all but finished in 1 minuteConcise annotation with a suggested fix and optional auto-remedation
SemgrepMedium – finds common issues with community rules, some missesPrimarily pattern-based, limited data flow analysis
Decent coverage with the right rules; misses advanced logic flaws 
Very fast (runs as lightweight CI)Custom rules possible, but require maintenance and security expertise
SonarQube
Low – missed serious issues in our testing
Mostly pattern-based (code quality focus)Basic coverage for known vulns; many issues flagged as “hotspots” require manual review Moderate (runs in CI/CD pipeline)Results in dashboard; risk of false sense of security if quality gate passes despite vulnerabilities
Vulnerability ClassSnyk CodeGitHub Advanced Security (CodeQL)SemgrepSonarQubeDryRun Security
SQL Injection (SQLi)
Cross-Site Scripting (XSS)
Server-Side Request Forgery (SSRF)
Auth Logic/IDOR
User Enumeration
Hardcoded Credentials
VulnerabilityDryRun SecuritySemgrepGitHub CodeQLSonarQubeSnyk Code
1. Remote Code Execution via Unsafe Deserialization
2. Code Injection via eval() Usage
3. SQL Injection in a Raw Database Query
4. Weak Encryption (AES ECB Mode)
5. Broken Access Control / Logic Flaw in Authentication
Total Found5/53/51/51/50/5
VulnerabilityDryRun SecuritySnykCodeQLSonarQubeSemgrep
Server-Side Request Forgery (SSRF)
(Hotspot)
Cross-Site Scripting (XSS)
SQL Injection (SQLi)
IDOR / Broken Access Control
Invalid Token Validation Logic
Broken Email Verification Logic
DimensionWhy It Matters
Surface
Entry points & data sources highlight tainted flows early.
Language
Code idioms reveal hidden sinks and framework quirks.
Intent
What is the purpose of the code being changed/added?
Design
Robustness and resilience of changing code.
Environment
Libraries, build flags, and infra metadata flag, infrastructure (IaC) all give clues around the risks in changing code.
KPIPattern-Based SASTDryRun CSA
Mean Time to Regex
3–8 hrs per noisy finding set
Not required
Mean Time to Context
N/A
< 1 min
False-Positive Rate
50–85 %< 5 %
Logic-Flaw Detection
< 5 %
90%+
Severity
CriticalHigh
Location
utils/authorization.py :L118
utils/authorization.py :L49 & L82 & L164
Issue
JWT Algorithm Confusion Attack:
jwt.decode() selects the algorithm from unverified JWT headers.
Insecure OIDC Endpoint Communication:
urllib.request.urlopen called without explicit TLS/CA handling.
Impact
Complete auth bypass (switch RS256→HS256, forge tokens with public key as HMAC secret).
Susceptible to MITM if default SSL behavior is weakened or cert store compromised.
Remediation
Replace the dynamic algorithm selection with a fixed, expected algorithm list. Change line 118 from algorithms=[unverified_header.get('alg', 'RS256')] to algorithms=['RS256'] to only accept RS256 tokens. Add algorithm validation before token verification to ensure the header algorithm matches expected values.
Create a secure SSL context using ssl.create_default_context() with proper certificate verification. Configure explicit timeout values for all HTTP requests to prevent hanging connections. Add explicit SSL/TLS configuration by creating an HTTPSHandler with the secure SSL context. Implement proper error handling specifically for SSL certificate validation failures.
Key Insight
This vulnerability arises from trusting an unverified portion of the JWT to determine the verification method itself
This vulnerability stems from a lack of explicit secure communication practices, leaving the application reliant on potentially weak default behaviors.
Security
June 17, 2026

What Your Git History Knows That Your Threat Model Doesn’t

How code churn, fragmented ownership, and years of rewrites quietly create security risk.

We found a customer file that kept generating security issues. The code itself wasn’t particularly remarkable, but its Git history was. Years of churn, fragmented ownership, and repeated rewrites revealed a security signal that would never appear in a call graph, architecture diagram, or traditional scanner.

Over time, a surprising number of people had modified that code. Different teams had touched it for different reasons across different eras of the product. An integration needed a new option, a workflow change, and a new deployment option was added. None of those changes looked reckless in isolation. In fact, most of them were probably reasonable at the time.

What caught our attention was the history that produced it.

Adam Tornhill’s Your Code as a Crime Scene has been influential for me because it treats code history as evidence. The core idea is simple: the way software changes over time often tells us more than the current snapshot of the code. Years of software engineering research have shown that code churn is one of the strongest predictors of defect density, while Tornhill extended that conversation into hotspots, ownership, and the human dynamics that shape software systems. The result is a useful reminder that software risk is often behavioral before it is technical.

History turns out to be a surprisingly good security signal.

The Many Hands Pattern

One of the patterns we have become increasingly interested in is fragmented ownership, or the many hands pattern. As revision counts increase, contributor counts naturally rise as well. The interesting cases are the ones where ownership never gets settled. The code becomes communal property, shaped by dozens of reasonable decisions made by people solving immediate problems. Over time, the original assumptions become harder to see, and the code begins carrying institutional knowledge that no individual contributor fully possesses.

That matters because many security failures are not failures of coding ability. They are failures of shared understanding. One engineer assumes a value is trusted because it always has been. Another introduces a workflow that changes where that value originates. A third extends the system without realizing the original boundary no longer exists. No individual change is obviously wrong, but the underlying security contract of the system has quietly changed.

What we often see next is something I think of as security contract renegotiation.

One of the simplest ways to spot it is by looking at cumulative additions and deletions over time. In relatively stable modules, growth tends to dominate. The code expands, but the core design remains recognizable. In unstable modules, deleted lines begin tracking added lines surprisingly closely. The code is not simply growing; it is being continuously rewritten. The team keeps returning to the same area of the system because the abstraction never quite settles into place.

This does not mean the engineering is poor. In many cases, it reflects a business that is evolving rapidly. New customers arrive, requirements change, integrations expand, and the software adapts. The security implication, however, is that the trust boundaries are moving. When a module is repeatedly reworked, the assumptions that originally governed it are repeatedly reworked as well. The code may look clean in its current state while still carrying years of accumulated security debt embedded in the decisions that led there.

None of this shows up particularly well in traditional security artifacts. An architecture diagram will not tell you that fifteen different people have modified a file over the last year. A call graph will not reveal that a subsystem has effectively been redesigned three times in eighteen months. A threat model rarely captures the organizational history that shaped a piece of software. Yet those signals often provide valuable clues about where security risk is likely to concentrate.

The rise of AI-generated software makes these patterns even more relevant. AI increases the number of people who can successfully modify software systems and allows engineers to move much faster across unfamiliar parts of a codebase. That is an enormous advantage, but it also means contributor breadth can grow faster than ownership depth. The code may be moving faster than the institutional memory can keep up with.

As we’ve continued building DryRun Security, one lesson keeps resurfacing: some of the most valuable security signals are hidden in the history of the code. Revisions, contributors, churn, ownership patterns, and repeated rewrites all help explain where risk is likely to emerge. They reveal pressures and behaviors that never appear in a vulnerability report but often explain why vulnerabilities appear in the first place.

Sometimes, the most important thing you can learn about a piece of software is not what it does today. It is whether anyone still owns the story of how it got there. Because eventually there comes a point where everybody has touched it, nobody owns it, and the history of the code becomes as important as the code itself.