소스 정보
- 저장소
- kousen/claude-code-training
- 최근 소스 활동
- 2025년 10월 29일 17:08
- 감지된 SKILL.md 언어
- 영어
- 스타
- 331
- 포크
- 345
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/kousen/claude-code-training --skill security-code-review명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
| name | Security Code Review |
| description | Identify security vulnerabilities and suggest secure coding practices |
When reviewing code for security issues, systematically check for common vulnerabilities and suggest secure alternatives.
Look for:
Vulnerable:
// SQL Injection
String query = "SELECT * FROM users WHERE username = '" + username + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);
// Command Injection
Runtime.getRuntime().exec("ping " + userInput);
Secure:
// Use Prepared Statements
String query = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();
// Avoid direct command execution; use APIs instead
// If unavoidable, validate and sanitize input
List<String> allowedHosts = Arrays.asList("localhost", "example.com");
if (allowedHosts.contains(userInput)) {
// proceed
}
Look for:
Vulnerable:
// Plain text password
user.setPassword(password);
// Weak session ID
String sessionId = user.getId() + System.currentTimeMillis();
Secure:
// Hash passwords with bcrypt
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String hashedPassword = encoder.encode(password);
user.setPassword(hashedPassword);
// Use cryptographically secure random session IDs
String sessionId = UUID.randomUUID().toString();
Look for:
Vulnerable:
// Logging sensitive data
logger.info("User password: " + password);
// Hardcoded secrets
String apiKey = "sk_live_1234567890abcdef";
// Detailed error messages
catch (Exception e) {
return "Database error: " + e.getMessage();
}
Secure:
// Mask sensitive data in logs
logger.info("User authenticated: " + username);
// Use environment variables
String apiKey = System.getenv("API_KEY");
// Generic error messages for users
catch (Exception e) {
logger.error("Database error", e); // Log details internally
return "An error occurred. Please try again later.";
}
Look for:
Vulnerable:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(userProvidedXml);
Secure:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(userProvidedXml);
Look for:
Vulnerable:
// No authorization check
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userRepository.findById(id);
}
// Path traversal
File file = new File("/uploads/" + filename);
Secure:
// Check authorization
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id, Principal principal) {
User currentUser = getCurrentUser(principal);
if (!currentUser.canAccess(id)) {
throw new AccessDeniedException("Unauthorized");
}
return userRepository.findById(id);
}
// Validate and sanitize file paths
Path basePath = Paths.get("/uploads").toAbsolutePath().normalize();
Path filePath = basePath.resolve(filename).normalize();
if (!filePath.startsWith(basePath)) {
throw new SecurityException("Invalid file path");
}
Look for:
Vulnerable:
# application.yml
spring:
profiles:
active: dev
debug: true
Secure:
# application-prod.yml
spring:
profiles:
active: prod
debug: false
# Add security headers
server:
servlet:
session:
cookie:
secure: true
http-only: true
Look for:
Vulnerable:
// Reflected XSS
document.getElementById('greeting').innerHTML =
"Hello " + userInput;
// DOM-based XSS
element.innerHTML = location.hash.substring(1);
Secure:
// Escape user input
document.getElementById('greeting').textContent =
"Hello " + userInput;
// Use safe methods
const div = document.createElement('div');
div.textContent = userInput;
element.appendChild(div);
Look for:
Vulnerable:
ObjectInputStream ois = new ObjectInputStream(userInputStream);
Object obj = ois.readObject(); // Dangerous!
Secure:
// Use safe alternatives like JSON
ObjectMapper mapper = new ObjectMapper();
MyObject obj = mapper.readValue(jsonString, MyObject.class);
// If ObjectInputStream required, validate class types
ObjectInputStream ois = new ObjectInputStream(userInputStream) {
@Override
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
if (!desc.getName().equals("com.example.SafeClass")) {
throw new InvalidClassException("Unauthorized deserialization");
}
return super.resolveClass(desc);
}
};
Look for:
Check:
# Maven
mvn versions:display-dependency-updates
mvn dependency-check:check
# npm
npm audit
# Python
pip-audit
Recommendation:
Look for:
Vulnerable:
@PostMapping("/login")
public void login(String username, String password) {
if (authenticate(username, password)) {
// Login successful
}
// No logging
}
Secure:
@PostMapping("/login")
public void login(String username, String password, HttpServletRequest request) {
boolean success = authenticate(username, password);
if (success) {
auditLog.info("Successful login: user={}, ip={}",
username, request.getRemoteAddr());
} else {
auditLog.warn("Failed login attempt: user={}, ip={}",
username, request.getRemoteAddr());
failedLoginTracker.record(username, request.getRemoteAddr());
}
}
Look for:
Vulnerable:
MessageDigest md = MessageDigest.getInstance("MD5");
Random random = new Random();
byte[] key = "hardcodedkey1234".getBytes();
Secure:
MessageDigest md = MessageDigest.getInstance("SHA-256");
SecureRandom random = new SecureRandom();
byte[] key = loadKeyFromSecureStorage();
Look for:
Secure Practices:
@RestController
@RequestMapping("/api/v1")
public class UserController {
// Rate limiting
@RateLimiter(name = "userApi")
@GetMapping("/users")
public Page<UserDto> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
Principal principal) {
// Validate input
if (size > 100) {
throw new IllegalArgumentException("Page size too large");
}
// Return only necessary fields
return userService.findAll(page, size)
.map(this::toDto);
}
}
When reviewing code, check:
When documenting security findings:
### [CRITICAL] SQL Injection in User Search
**Location**: UserController.java:45
**Issue**: User input is concatenated directly into SQL query, allowing SQL injection attacks.
**Vulnerable Code**:
```java
String query = "SELECT * FROM users WHERE name LIKE '%" + searchTerm + "%'";
Impact: Attackers can execute arbitrary SQL, potentially accessing all database data or modifying records.
Recommendation: Use parameterized queries with PreparedStatement.
Fixed Code:
String query = "SELECT * FROM users WHERE name LIKE ?";
PreparedStatement stmt = connection.prepareStatement(query);
stmt.setString(1, "%" + searchTerm + "%");
Severity: Critical CVSS Score: 9.8 (Critical) Remediation Priority: Immediate
## When This Skill Activates
This skill automatically activates when:
- Reviewing code for security vulnerabilities
- Performing security audits
- Analyzing authentication/authorization code
- Checking for OWASP Top 10 vulnerabilities
- Questions about secure coding practices
- Reviewing API security
- Analyzing cryptographic implementations
SOC 직업 분류 기준