| name | eastsword-dfyx-code-security-review |
| description | Expert-level code security audit skill using deep data flow analysis, taint tracking, and business logic understanding across 9 languages |
| triggers | ["audit this code for security vulnerabilities","perform a security code review","find security issues in this project","analyze code for security flaws","run security audit on codebase","check for vulnerabilities in source code","conduct white-box security analysis","review code security with dfyx methodology"] |
EastSword DFYX Code Security Review
Skill by ara.so — Security Skills collection.
Expert-level code security audit skill developed by the EastSword (东方隐侠) team. Performs comprehensive white-box static analysis using a five-phase standardized audit protocol with deep data flow analysis, taint tracking, and business logic understanding.
Overview
dfyx_code_security_review is a professional code security audit skill designed for AI coding agents. It employs white-box static analysis methodology through a five-phase standardized protocol to systematically discover and validate security vulnerabilities in source code.
Core Capabilities
- 9 Languages: Java, Python, Go, PHP, JavaScript/Node.js, C/C++, .NET/C#, Ruby, Rust
- 14 Frameworks: Spring Boot, Django, Flask, FastAPI, Express, Koa, Gin, Laravel, Rails, ASP.NET Core, Rust Web, NestJS, Fastify, MyBatis
- 10 Security Dimensions: Injection, Authentication, Authorization, Deserialization, File Operations, SSRF, Cryptography, Configuration, Business Logic, Supply Chain
- Triple-Track Audit Model: Sink-driven + Control-driven + Config-driven
- Five-Phase Protocol: Reconnaissance → Pattern Matching → Taint Tracking → Validation → Reporting
- Rich Case Library: Based on real-world WooYun vulnerability cases (2010-2016)
Installation
Clone or copy this skill to your AI client's skills directory:
git clone https://github.com/EastSword/skill-dfyx_code_security_review.git ~/.claude/skills/eastsword-dfyx-code-security-review
git clone https://github.com/EastSword/skill-dfyx_code_security_review.git ~/Library/Application\ Support/Cursor/skills/eastsword-dfyx-code-security-review
cd ~/.claude/skills/eastsword-dfyx-code-security-review
pip install -r requirements.txt
Five-Phase Audit Protocol
Phase 1: Reconnaissance & Mapping (10%)
Objective: Understand architecture and identify attack surface.
[RECON] Technology Stack: Spring Boot 2.7.3 + MyBatis 3.5.10 + Shiro 1.9.0
[RECON] Attack Surface:
- REST API: 47 endpoints (28 authenticated, 19 public)
- File Upload: 3 endpoints (/api/upload, /admin/import, /user/avatar)
- Template Engine: Thymeleaf (potential SSTI)
- Database: MySQL 8.0.30 (84 SQL queries identified)
[RECON] Security Controls:
- Authentication: Shiro + JWT
- Authorization: @RequiresPermissions annotations (coverage: 67%)
- Input Validation: @Validated + Hibernate Validator (coverage: 45%)
Key Activities:
- Identify entry points (REST endpoints, file uploads, external integrations)
- Map data flows from sources to sinks
- Enumerate security controls and their coverage
- Build architectural diagram with trust boundaries
Phase 2: Parallel Pattern Matching (30%)
Objective: Identify high-risk code patterns across all dimensions.
from scripts.pattern_scanner import PatternScanner
scanner = PatternScanner(language='java')
results = scanner.scan('/path/to/project', dimensions=['D1', 'D2', 'D3', 'D4', 'D5'])
[PATTERN] SQL Injection Candidates: 12 locations
- UserService.java:145 - String concatenation in SQL query
- OrderDao.xml:78 - Dynamic SQL with ${} placeholder
[PATTERN] Command Injection Candidates: 3 locations
- FileProcessor.java:234 - Runtime.exec() with user input
[PATTERN] Authentication Bypass Candidates: 5 locations
- AdminController.java:89 - Missing @RequiresAuthentication
- ReportController.java:156 - Direct database authentication check
Detection Rules:
- pattern: executeQuery\s*\(\s*[\w\s]+\s*\+
severity: CRITICAL
description: String concatenation in SQL query
- pattern: \$\{[\w\.]+\}
file_types: [.xml]
severity: CRITICAL
description: MyBatis unsafe placeholder
- pattern: os\.system\(.*input.*\)
severity: CRITICAL
description: User input in os.system()
- pattern: subprocess\.(call|run|Popen)\(.*request\.
severity: CRITICAL
description: User input in subprocess execution
Phase 3: Deep Taint Tracking & Validation (40%)
Objective: Trace data flows from sources to sinks and validate exploitability.
from scripts.data_flow_analyzer import TaintAnalyzer
analyzer = TaintAnalyzer()
result = analyzer.trace_flow(
source='HttpServletRequest.getParameter("id")',
sink='executeQuery(sql)',
project_path='/path/to/project'
)
[TAINT] Flow Found: REQUEST → SQL_QUERY
Source: UserController.java:45
→ String userId = request.getParameter("userId");
Flow Path:
1. UserController.java:45 → userId (TAINTED)
2. UserController.java:47 → userService.getUserById(userId) (TAINTED)
3. UserService.java:89 → buildQuery(userId) (TAINTED)
4. UserService.java:102 → "SELECT * FROM users WHERE id=" + userId (TAINTED)
5. UserService.java:103 → statement.executeQuery(sql) (SINK - NO SANITIZATION)
Sanitization: NONE
Validation: NONE
Exploitable: YES
POC:
GET /api/user?userId=1' UNION SELECT password FROM admin_users--
Taint Analysis Features:
- Source Identification: HTTP parameters, file reads, environment variables, database queries
- Sanitization Detection: Input validation, encoding, parameterized queries, allowlist filtering
- Sink Detection: SQL execution, command execution, file operations, template rendering, JNDI lookup
- Context-Aware Analysis: Different rules for different contexts (SQL, OS command, XSS, etc.)
[TAINT] Complex Flow: REQUEST → SESSION → DATABASE → TEMPLATE
Stage 1: User input stored in session
UserController.java:67 → session.setAttribute("theme", themeParam)
Stage 2: Session value retrieved in different request
ThemeController.java:34 → String theme = session.getAttribute("theme")
Stage 3: Theme value used in database query
ThemeService.java:89 → "SELECT * FROM themes WHERE name='" + theme + "'"
Stage 4: Query result rendered in template
theme.html:12 → <div th:text="${themeName}"></div> (XSS via SQLi)
Attack Chain: Stored XSS via SQL Injection
Exploitable: YES
Phase 4: Validation & Attack Chain Construction (15%)
Objective: Validate vulnerabilities and construct multi-stage attack chains.
[VALIDATION] SQL Injection in UserService.getUserById()
Test 1: Syntax Error Injection
Input: userId=1'
Expected: SQL syntax error
Result: ✓ "You have an error in your SQL syntax"
Test 2: Boolean-based Blind SQLi
Input: userId=1 AND 1=1
Response Time: 0.123s
Input: userId=1 AND 1=2
Response Time: 0.125s
Result: ✓ Different responses confirm vulnerability
Test 3: Union-based SQLi
Input: userId=1 UNION SELECT 1,2,3,4,5--
Result: ✓ Column count: 5
Test 4: Data Extraction
Input: userId=1 UNION SELECT null,username,password,null,null FROM admin_users--
Result: ✓ Admin credentials leaked
[ATTACK_CHAIN] Privilege Escalation via SQL Injection
Step 1: Exploit SQLi to extract admin password hash
→ /api/user?userId=1 UNION SELECT password FROM admin_users WHERE role='ADMIN'--
Step 2: Crack password hash (MD5 without salt)
→ hashcat -m 0 -a 0 hash.txt rockyou.txt
Step 3: Login as admin
→ POST /api/login {"username":"admin","password":"cracked_password"}
Step 4: Access admin panel
→ GET /admin/dashboard
Impact: Complete system compromise
Likelihood: HIGH (weak password hashing + no rate limiting)
Attack Chain Patterns:
chain_type: privilege_escalation
vulnerabilities:
- SQL Injection → Password Hash Extraction
- Weak Cryptography → Hash Cracking
- Missing Rate Limiting → Brute Force
- Insufficient Authorization → Admin Access
chain_type: data_exfiltration
vulnerabilities:
- Path Traversal → Configuration File Read
- Hardcoded Credentials → Database Access
- Missing Network Segmentation → Internal Network Access
- SSRF
Phase 5: Structured Reporting (5%)
Objective: Generate comprehensive, actionable security audit report.
from scripts.report_generator import ReportGenerator
report = ReportGenerator()
report.add_vulnerability({
'id': 'VUL-001',
'title': 'SQL Injection in User Query',
'severity': 'CRITICAL',
'cvss': 9.8,
'dimension': 'D1-Injection',
'location': 'UserService.java:102',
'description': 'String concatenation in SQL query allows SQL injection',
'exploitation': 'Confirmed via manual testing',
'impact': 'Complete database compromise, authentication bypass',
'poc': 'GET /api/user?userId=1\' UNION SELECT password FROM admin_users--',
'remediation': [
'Use PreparedStatement with parameterized queries',
'Implement input validation with allowlist',
'Apply least privilege principle to database user'
],
'code_vulnerable': '''
String sql = "SELECT * FROM users WHERE id=" + userId;
statement.executeQuery(sql);
''',
'code_fixed': '''
String sql = "SELECT * FROM users WHERE id=?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, userId);
stmt.executeQuery();
'''
})
report.generate('audit_report.md', format='markdown')
10 Security Dimensions
D1: Injection Vulnerabilities
Coverage: SQL, Command, LDAP, SSTI, SpEL, JNDI, XSS, XXE
patterns = {
'java': [
r'executeQuery\s*\(\s*[\w\s]+\s*\+',
r'createQuery\s*\(\s*".*"\s*\+',
r'\$\{[\w\.]+\}'
],
'python': [
r'execute\s*\(\s*["\'].*%.*["\']',
r'execute\s*\(\s*f["\'].*\{.*\}',
r'raw\s*\(\s*["\'].*["\'].*\+'
],
'php': [
r'mysql_query\s*\(\s*\$',
r'->query\s*\(\s*\$',
r'DB::select\s*\(\s*["\'].*\.',
]
}
patterns = {
'java': [
r'Runtime\.getRuntime\(\)\.exec\(',
r'ProcessBuilder\s*\(\s*.*request',
r'new\s+Process\w*\s*\(',
],
'python': [
r'os\.system\s*\(',
r'subprocess\.(call|run|Popen)\(',
r'eval\s*\(',
r'exec\s*\(',
],
'php': [
r'exec\s*\(',
r'shell_exec\s*\(',
r'system\s*\(',
r'passthru\s*\(',
r'popen\s*\(',
r'proc_open\s*\(',
]
}
Example: SSTI Detection (Python)
from flask import Flask, request, render_template_string
@app.route('/hello')
def hello():
name = request.args.get('name', 'Guest')
template = '<h1>Hello ' + name + '!</h1>'
return render_template_string(template)
from flask import Flask, request, render_template
from markupsafe import escape
@app.route('/hello')
def hello():
name = escape(request.args.get('name', 'Guest'))
return render_template('hello.html', name=name)
D2: Authentication Vulnerabilities
Coverage: Token management, Session handling, JWT flaws, Filter chain bypass
public class DatabaseConfig {
private static final String DB_USER = "admin";
private static final String DB_PASS = "P@ssw0rd123";
public Connection getConnection() {
return DriverManager.getConnection(
"jdbc:mysql://localhost:3306/db",
DB_USER, DB_PASS
);
}
}
public class DatabaseConfig {
private final String dbUser = System.getenv("DB_USER");
private final String dbPass = System.getenv("DB_PASSWORD");
public Connection getConnection() {
if (dbUser == null || dbPass == null) {
throw new IllegalStateException("Database credentials not configured");
}
DriverManager.getConnection(
System.getenv(),
dbUser, dbPass
);
}
}
JWT Vulnerability Detection:
import jwt
def verify_token(token):
payload = jwt.decode(token, options={"verify_signature": False})
return payload['user_id']
import jwt
from jwt.exceptions import InvalidTokenError
def verify_token(token):
try:
secret_key = os.getenv('JWT_SECRET_KEY')
payload = jwt.decode(
token,
secret_key,
algorithms=['HS256'],
options={"verify_signature": True}
)
return payload['user_id']
except InvalidTokenError:
raise AuthenticationError("Invalid token")
D3: Authorization Vulnerabilities
Coverage: IDOR, Horizontal privilege escalation, Missing function-level access control, CRUD consistency
@GetMapping("/api/orders/{orderId}")
public Order getOrder(@PathVariable Long orderId) {
return orderService.findById(orderId);
}
@GetMapping("/api/orders/{orderId}")
public Order getOrder(@PathVariable Long orderId,
@AuthenticationPrincipal User currentUser) {
Order order = orderService.findById(orderId);
if (!order.getUserId().equals(currentUser.getId())
&& !currentUser.hasRole("ADMIN")) {
throw new AccessDeniedException("Cannot access this order");
}
return order;
}
CRUD Consistency Check:
[AUTHORIZATION] CRUD Consistency Analysis: /api/users endpoint
CREATE (POST /api/users):
✓ @RequiresPermissions("user:create")
READ (GET /api/users/{id}):
✗ No authorization annotation
✗ No ownership check in code
UPDATE (PUT /api/users/{id}):
✓ @RequiresPermissions("user:update")
✗ No ownership check in code
DELETE (DELETE /api/users/{id}):
✓ @RequiresPermissions("user:delete")
✓ Ownership check: if (user.getId() != currentUser.getId())
Issue: READ and UPDATE lack ownership verification
Impact: Horizontal privilege escalation
Severity: HIGH
D4: Deserialization Vulnerabilities
Coverage: Java Gadget chains, Python pickle, PHP unserialize
@PostMapping("/api/import")
public void importData(@RequestBody byte[] data) {
try {
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(data)
);
Object obj = ois.readObject();
processData(obj);
} catch (Exception e) {
log.error("Import failed", e);
}
}
@PostMapping("/api/import")
public void importData(@RequestBody String jsonData) {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
ImportRequest request = mapper.readValue(jsonData, ImportRequest.class);
processData(request);
}
public class SafeObjectInputStream {
Set<String> ALLOWED_CLASSES = Set.of(
,
,
);
Class<?> resolveClass(ObjectStreamClass desc)
IOException, ClassNotFoundException {
(!ALLOWED_CLASSES.contains(desc.getName())) {
(
+ desc.getName()
);
}
.resolveClass(desc);
}
}
D5: File Operation Vulnerabilities
Coverage: Upload bypass, Path traversal, XXE, Zip slip
from flask import Flask, request, send_file
import os
@app.route('/download')
def download():
filename = request.args.get('file')
filepath = os.path.join('/var/www/uploads', filename)
return send_file(filepath)
from flask import Flask, request, send_file, abort
import os
from pathlib import Path
@app.route('/download')
def download():
filename = request.args.get('file')
base_dir = Path('/var/www/uploads').resolve()
requested_path = (base_dir / filename).resolve()
if not str(requested_path).startswith(str(base_dir)):
abort(403, "Path traversal attempt detected")
if not requested_path.exists() or not requested_path.is_file():
abort(404)
return send_file(requested_path)
File Upload Security:
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
String filename = file.getOriginalFilename();
File dest = new File("/uploads/" + filename);
file.transferTo(dest);
return "Upload successful";
}
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
if (file.getSize() > 10 * 1024 * 1024) {
throw new FileTooLargeException();
}
String contentType = file.getContentType();
List<String> allowed = Arrays.asList("image/jpeg", "image/png", "application/pdf");
if (!allowed.contains(contentType)) {
();
}
file.getOriginalFilename();
originalName.substring(originalName.lastIndexOf());
(!Arrays.asList(, , ).contains(extension.toLowerCase())) {
();
}
[] header = [];
file.getInputStream().read(header);
(!isValidMagicBytes(header, contentType)) {
();
}
UUID.randomUUID().toString() + extension;
Paths.get().toAbsolutePath().normalize();
uploadDir.resolve(safeFilename);
(!filePath.startsWith(uploadDir)) {
();
}
file.transferTo(filePath.toFile());
Files.setPosixFilePermissions(filePath, PosixFilePermissions.fromString());
+ safeFilename;
}
D6: SSRF Vulnerabilities
Coverage: URL injection, Protocol restriction bypass, Cloud metadata access
import requests
from flask import Flask, request
@app.route('/fetch')
def fetch():
url = request.args.get('url')
response = requests.get(url)
return response.text
import requests
from flask import Flask, request, abort
from urllib.parse import urlparse
import ipaddress
ALLOWED_SCHEMES = ['http', 'https']
BLOCKED_IPS = [
'127.0.0.0/8',
'10.0.0.0/8',
'172.16.0.0/12',
'192.168.0.0/16',
'169.254.0.0/16',
'::1/128',
'fc00::/7',
]
def is_safe_url(url):
try:
parsed = urlparse(url)
if parsed.scheme not ALLOWED_SCHEMES:
socket
ip_str = socket.gethostbyname(parsed.hostname)
ip = ipaddress.ip_address(ip_str)
blocked_range BLOCKED_IPS:
ip ipaddress.ip_network(blocked_range):
parsed.port [, , , , , , , ]:
Exception:
():
url = request.args.get()
url:
abort(, )
is_safe_url(url):
abort(, )
:
response = requests.get(
url,
timeout=,
allow_redirects=,
stream=
)
content =
chunk response.iter_content(chunk_size=):
content += chunk
(content) > * :
abort(, )
content.decode()
requests.exceptions.RequestException e:
abort(, )
D7: Cryptography Vulnerabilities
Coverage: Weak algorithms, Hard-coded keys, Improper key derivation, Insecure random
public class CryptoUtils {
private static final String SECRET_KEY = "MySecretKey12345";
public static String encrypt(String data) throws Exception {
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
SecretKeySpec key = new SecretKeySpec(
SECRET_KEY.getBytes(), "DES"
);
cipher.init(Cipher.ENCRYPT_MODE, key);
return Base64.getEncoder().encodeToString(
cipher.doFinal(data.getBytes())
);
}
}
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
public class SecureCryptoUtils {
;
;
;
;
SecretKey {
System.getenv();
(encodedKey == ) {
();
}
[] decodedKey = Base64.getDecoder().decode(encodedKey);
(decodedKey, );
}
String Exception {
getKey();
[] iv = [IV_SIZE];
();
random.nextBytes(iv);
Cipher.getInstance(ALGORITHM);
(TAG_SIZE, iv);
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
[] ciphertext = cipher.doFinal(plaintext.getBytes());
[] combined = [iv.length + ciphertext.length];
System.arraycopy(iv, , combined, , iv.length);
System.arraycopy(ciphertext, , combined, iv.length, ciphertext.length);
Base64.getEncoder().encodeToString(combined);
}
String Exception {
getKey();
[] combined = Base64.getDecoder().decode(encryptedData);
[] iv = [IV_SIZE];
[] ciphertext = [combined.length - IV_SIZE];
System.arraycopy(combined, , iv, , IV_SIZE);
System.arraycopy(combined, IV_SIZE, ciphertext, , ciphertext.length);
Cipher.getInstance(ALGORITHM);
(TAG_SIZE, iv);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
[] plaintext = cipher.doFinal(ciphertext);
(plaintext, );
}
String Exception {
KeyGenerator.getInstance();
keyGen.init(KEY_SIZE, ());
Sec