BlogSecurity

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.

20 min readUpdated December 2025

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).

70%

of applications have security flaws (Veracode)

6 months

Average time to detect a breach

85%

of breaches involve human error

Common Code Vulnerabilities

SQL Injection (SQLi)

CWE-89Critical

Occurs 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-79High

Allows 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-352Medium

Tricks 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-502Critical

Occurs 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 parsing

Prevention:

  • Never deserialize untrusted data
  • Use simple data formats like JSON
  • Implement integrity checks (signatures)
  • Isolate deserialization in sandboxed environments

Broken Authentication

CWE-287Critical

Weak 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-200High

Improper 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.

Tools: Semgrep, SonarQube, Checkmarx, TigerGate
+ Early detection
+ Finds root cause
- False positives
- Can't find runtime issues

Software Composition Analysis (SCA)

Scans dependencies for known vulnerabilities in third-party libraries.

Tools: Snyk, Dependabot, OSV-Scanner, TigerGate
+ Finds dependency vulns
+ CVE database matching
- Only finds known issues
- Doesn't scan your code

Dynamic Application Security Testing (DAST)

Tests running applications by simulating attacks from the outside.

Tools: OWASP ZAP, Burp Suite, Nuclei, TigerGate
+ Finds runtime issues
+ Tests like attacker
- Needs running app
- Can miss code paths

Secrets Detection

Scans code for hardcoded API keys, passwords, and credentials.

Tools: Gitleaks, TruffleHog, detect-secrets, TigerGate
+ Prevents credential leaks
+ Easy to implement
- Limited to known patterns
- Possible false positives

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