Code Security Vulnerabilities: Complete Guide
Understand common security vulnerabilities in code, how to detect them, and proven strategies for prevention. Essential knowledge for every developer.
Why Code Security Matters
Security vulnerabilities in code can lead to data breaches, financial loss, regulatory penalties, and reputation damage. The average cost of a data breach is $4.45 million (IBM, 2023).
of applications have security flaws (Veracode)
Average time to detect a breach
of breaches involve human error
Common Code Vulnerabilities
SQL Injection (SQLi)
CWE-89CriticalOccurs when untrusted data is sent to an interpreter as part of a command or query. Attackers can read, modify, or delete database data.
Example:
// Vulnerable
const query = "SELECT * FROM users WHERE id = " + userId;
// Secure (parameterized)
const query = "SELECT * FROM users WHERE id = ?";
db.query(query, [userId]);Prevention:
- Use parameterized queries or prepared statements
- Use ORM frameworks that handle escaping
- Validate and sanitize all input
- Apply principle of least privilege to DB accounts
Cross-Site Scripting (XSS)
CWE-79HighAllows attackers to inject malicious scripts into web pages viewed by other users. Can steal cookies, session tokens, or deface websites.
Example:
// Vulnerable
element.innerHTML = userInput;
// Secure (text only)
element.textContent = userInput;
// Secure (with sanitization)
element.innerHTML = DOMPurify.sanitize(userInput);Prevention:
- Encode output based on context (HTML, JS, URL, CSS)
- Use Content Security Policy (CSP) headers
- Sanitize HTML input with libraries like DOMPurify
- Use frameworks that auto-escape by default
Cross-Site Request Forgery (CSRF)
CWE-352MediumTricks authenticated users into performing unintended actions. Can change passwords, transfer funds, or modify settings.
Example:
// Protection with CSRF token
<form method="POST">
<input type="hidden" name="csrf_token" value="{{csrf_token}}">
<!-- form fields -->
</form>
// Verify on server
if (request.csrf_token !== session.csrf_token) {
throw new Error('Invalid CSRF token');
}Prevention:
- Use anti-CSRF tokens on all state-changing requests
- Verify Origin and Referer headers
- Use SameSite cookie attribute
- Require re-authentication for sensitive actions
Insecure Deserialization
CWE-502CriticalOccurs when untrusted data is used to abuse application logic or achieve remote code execution. Common in Java, PHP, and Python applications.
Example:
// Vulnerable (Python)
data = pickle.loads(user_input) # Never do this!
// Secure
data = json.loads(user_input) # Use safe formats
# Validate schema after parsingPrevention:
- Never deserialize untrusted data
- Use simple data formats like JSON
- Implement integrity checks (signatures)
- Isolate deserialization in sandboxed environments
Broken Authentication
CWE-287CriticalWeak authentication mechanisms that allow attackers to compromise passwords, session tokens, or exploit implementation flaws.
Example:
// Weak
if (password === storedPassword) { /* OK */ }
// Secure
const match = await bcrypt.compare(password, hashedPassword);
// Session security
app.use(session({
secret: process.env.SESSION_SECRET,
cookie: { secure: true, httpOnly: true, sameSite: 'strict' }
}));Prevention:
- Use strong password hashing (bcrypt, Argon2)
- Implement multi-factor authentication
- Use secure session management
- Rate limit authentication attempts
Sensitive Data Exposure
CWE-200HighImproper protection of sensitive data like passwords, credit cards, health records. Can occur in transit or at rest.
Example:
// Bad: Sensitive data in logs
console.log(`User ${user.email} with card ${card.number}`);
// Good: Mask sensitive data
console.log(`User ${maskEmail(user.email)}`);
// Good: Encrypt at rest
const encrypted = crypto.encrypt(sensitiveData, key);Prevention:
- Encrypt all sensitive data at rest and in transit
- Don't store sensitive data unnecessarily
- Use strong encryption algorithms (AES-256)
- Disable caching for sensitive responses
How to Detect Vulnerabilities
Static Application Security Testing (SAST)
Analyzes source code for vulnerabilities without executing the program.
Software Composition Analysis (SCA)
Scans dependencies for known vulnerabilities in third-party libraries.
Dynamic Application Security Testing (DAST)
Tests running applications by simulating attacks from the outside.
Secrets Detection
Scans code for hardcoded API keys, passwords, and credentials.
How Vulnerabilities Enter Your Codebase
Understanding where vulnerabilities originate is the first step toward eliminating them. Most security flaws are not introduced by careless developers acting alone — they emerge from systemic gaps in how software is designed, built, and maintained. The MITRE CWE Top 25 consistently shows the same weakness classes year after year, which tells us that the industry keeps repeating the same mistakes rather than inventing new ones.
In practice, vulnerabilities enter a codebase through four primary channels. First, hand-written application code introduces injection flaws (CWE-89, CWE-78), broken access control (CWE-862, CWE-863), and memory-safety issues (CWE-787 out-of-bounds write remains the number one weakness in MITRE's rankings). Second, third-party dependencies bring known CVEs into your build — the average modern application pulls in hundreds of transitive packages, and incidents like Log4Shell (CVE-2021-44228) proved that a single logging library can expose an entire organization. Third, infrastructure-as-code and configuration files leak overly permissive IAM policies, public storage buckets, and disabled encryption settings. Fourth, secrets committed to version control — API keys, database passwords, cloud credentials — give attackers direct access without needing to exploit anything at all.
Each channel demands a different detection technique, which is why mature security programs layer SAST, SCA, IaC scanning, and secrets detection rather than relying on a single tool. A SAST engine will never flag a vulnerable version of OpenSSL in your lockfile, and a dependency scanner will never notice a SQL query built by string concatenation in your own code.
The Cost of Late Detection
The economics of vulnerability remediation are heavily front-loaded. Research from NIST and IBM consistently shows that a defect fixed during design or coding costs a fraction of one fixed in production — commonly cited multipliers range from 6x at testing to 30x or more once the flaw ships. Beyond direct engineering time, a production vulnerability carries incident response costs, potential breach notification obligations under GDPR or state privacy laws, and audit findings that can delay SOC 2 or ISO 27001 certifications.
- In the IDE: a vulnerable pattern flagged as the developer types costs seconds to fix — the context is fresh and no review cycle is needed.
- In the pull request: a finding caught by CI scanning costs minutes to hours, but still blocks the flaw before merge.
- In staging: DAST or penetration testing findings require a ticket, triage, prioritization, and a full release cycle to remediate.
- In production: the same flaw may require emergency patching, log forensics to confirm it was not exploited, and customer communication.
Prioritizing Findings: Not Every Vulnerability Is Equal
Teams that turn on security scanning for the first time often face hundreds or thousands of findings. Trying to fix everything at once guarantees fixing nothing. Effective triage combines several signals rather than sorting purely by CVSS score:
- Exploitability: Is the vulnerable code reachable from user input? A SQL injection in an internal admin script behind VPN access is a different risk than one on a public login form. CISA's Known Exploited Vulnerabilities (KEV) catalog and EPSS scores help identify which CVEs attackers actually weaponize.
- Data sensitivity: Flaws in services handling payment data (PCI-DSS scope), health records (HIPAA), or credentials deserve elevated priority regardless of raw severity.
- Blast radius: A vulnerability in shared authentication middleware affects every downstream service; the same class of bug in a single endpoint does not.
- Compensating controls: A WAF rule, network segmentation, or runtime enforcement may reduce urgency — but should never be treated as a permanent fix.
A pragmatic rollout looks like this: block new critical and high findings in CI immediately, so the backlog stops growing. Then burn down existing criticals within 30 days, highs within 90, and schedule mediums into normal sprint work. Platforms like TigerGate support this workflow by correlating SAST, SCA, and secrets findings into a single deduplicated view per repository, so teams triage one prioritized list instead of four separate reports.
Handling False Positives Without Losing Trust
False positives are the fastest way to kill a security program. When developers learn that a scanner cries wolf, they start ignoring it entirely — including the true positives. Reduce noise by tuning rulesets per language and framework, suppressing findings with documented justifications tracked in code review, and preferring dataflow-aware analysis (which follows tainted input from source to sink) over naive pattern matching. Track your true-positive rate as a program metric: if fewer than half of triaged findings are actionable, the ruleset needs pruning before enforcement widens.
Frequently Asked Questions
What is the difference between a CWE and a CVE?
A CWE (Common Weakness Enumeration) describes a category of flaw — for example, CWE-89 is SQL injection as a class of mistake. A CVE (Common Vulnerabilities and Exposures) identifies a specific instance of a vulnerability in a specific product and version, such as CVE-2021-44228 in Log4j. SAST tools report CWEs in your own code; SCA tools report CVEs in your dependencies.
How often should we scan our code for vulnerabilities?
Scan on every pull request for incremental changes, and run full scans on the default branch at least daily. Dependency vulnerabilities require continuous monitoring because new CVEs are published against existing versions every day — your code can become vulnerable overnight without a single commit.
Do frameworks like React or Django make these vulnerabilities obsolete?
Modern frameworks eliminate entire bug classes by default — React escapes output and Django parameterizes ORM queries. But escape hatches like dangerouslySetInnerHTML, raw SQL queries, and template filters that mark content as safe reintroduce the same risks. Framework defaults reduce vulnerability density; they do not remove the need for scanning and review.
Is one scanning approach enough?
No. SAST, SCA, DAST, and secrets detection each cover blind spots the others miss. OWASP recommends combining static and dynamic techniques, and compliance frameworks such as PCI-DSS explicitly require both code review processes and vulnerability scanning of running systems.
Scan Your Code for Vulnerabilities
TigerGate combines SAST, SCA, secrets detection, and DAST in one platform. Find vulnerabilities before attackers do.
Start Free Security Scan