agentleFS
quruhao4800quruhao4800/agent-workflow/skills/meta/security-review/SKILL.md

security-review

Skill1 starsChanged 6 months agoMITView on GitHub

Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment/sensitive features. Provides comprehensive security checklist and patterns for Java/Spring Boot.

  • Reads credentials

192 other projects use a version of this, 33 of them edited.

Adopted by

Most recently taken up by

Used with

Projects with it also use linkerd-patterns, dependency-cve-sweep and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • xfstudioSkill

    linkerd-patterns

    Implement Linkerd service mesh patterns for lightweight, security-focused service mesh deployments. Use when setting up Linkerd, configuring traffic policies, or implementing zero-trust networking with minimal overhead.

    Also in 5 projects that use this

  • berntpoppSkill

    dependency-cve-sweep

    Use when handling Dependabot PRs, CodeQL/Trivy alerts, or doing a routine dependency/CVE sweep for this repo.

    Also in 12 projects that use this

  • berntpoppSkill

    fleet-standard-adoption

    Use when bringing this repo into compliance with a GeneFoundry fleet standard (tool-naming, response-envelope, container-hardening, versioning, MCP transport, or logging) or closing its tracking issue.

    Also in 12 projects that use this

  • HABUBUSSSkill

    project-guidelines-example

    Also in 16 projects that use this

  • niloykumarbarmanSkill

    agent-sort

    Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

    Also in 13 projects that use this

  • royaluniondesign-sysSkill

    configure-ecc

    Interactive installer for Everything Claude Code — guides users through selecting and installing skills and rules to user-level or project-level directories, verifies paths, and optionally optimizes installed files.

    Also in 11 projects that use this

  • +2 more from berntpopp

The file

Files
SKILL.md

Security Review Skill

This skill ensures all code follows security best practices and identifies potential vulnerabilities.

When to Activate

  • Implementing authentication or authorization
  • Handling user input or file uploads
  • Creating new API endpoints
  • Working with secrets or credentials
  • Implementing payment features
  • Storing or transmitting sensitive data
  • Integrating third-party APIs

Security Checklist

1. Secrets Management

❌ NEVER Do This

private static final String API_KEY = "sk-proj-xxxxx";  // Hardcoded secret
private static final String DB_PASSWORD = "password123"; // In source code

✅ ALWAYS Do This

// application.yml
// api.key: ${API_KEY}

@Value("${api.key}")
private String apiKey;

// Or use @ConfigurationProperties
// Note: record requires Java 16+. For Java 11–15, use a @Data @ConfigurationProperties class instead.
@ConfigurationProperties(prefix = "app")
public record AppConfig(String apiKey, String dbUrl) {}

Verification Steps

  • No hardcoded API keys, tokens, or passwords in source code
  • All secrets in environment variables or Vault
  • .env files in .gitignore
  • No secrets in git history
  • Production secrets managed via environment configuration

2. Input Validation

Always Validate User Input (Bean Validation)

// Note: record requires Java 16+. For Java 11–15, use @Data @Builder @NoArgsConstructor @AllArgsConstructor class instead.
public record CreateUserRequest(
    @NotBlank @Email String email,
    @NotBlank @Size(min = 1, max = 100) String name,
    @Min(0) @Max(150) Integer age
) {}

@RestController
@Validated
public class UserController {
    @PostMapping("/api/v1/users")
    public ResponseEntity<UserResponse> createUser(
            @RequestBody @Valid CreateUserRequest request) {
        return ResponseEntity.status(201).body(userService.create(request));
    }
}

File Upload Validation

@PostMapping("/upload")
public ResponseEntity<String> upload(@RequestParam MultipartFile file) {
    long maxSize = 5 * 1024 * 1024; // 5MB
    if (file.getSize() > maxSize) {
        throw new IllegalArgumentException("File too large (max 5MB)");
    }

    List<String> allowedTypes = List.of("image/jpeg", "image/png", "image/gif");
    if (!allowedTypes.contains(file.getContentType())) {
        throw new IllegalArgumentException("Invalid file type");
    }

    String filename = StringUtils.cleanPath(file.getOriginalFilename());
    if (filename.contains("..")) {
        throw new IllegalArgumentException("Invalid file path");
    }

    return ResponseEntity.ok("Uploaded");
}

Verification Steps

  • All user inputs validated with @Valid and Bean Validation annotations
  • File uploads restricted (size, type, path traversal check)
  • No direct use of user input in queries
  • Whitelist validation (not blacklist)
  • Error messages don't leak sensitive info

3. SQL Injection Prevention

❌ NEVER Concatenate SQL

// DANGEROUS - SQL Injection vulnerability
String query = "SELECT * FROM users WHERE email = '" + userEmail + "'";
jdbcTemplate.query(query, ...);

✅ ALWAYS Use Parameterized Queries

// Safe - MyBatis Plus: always #{}, never ${}
// #{email} → prepared statement placeholder (safe)
// ${email} → string interpolation directly into SQL (injection risk)
List<UserDO> selectByEmail(@Param("email") String email); // XML: WHERE email = #{email}

// Safe - parameterized query with JdbcTemplate
String sql = "SELECT * FROM users WHERE email = ?";
jdbcTemplate.query(sql, rowMapper, userEmail);

// Safe - JPA/JPQL named parameter
@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmail(@Param("email") String email);

// Safe - Spring Data method naming (automatically parameterized)
Optional<User> findByEmail(String email);

Verification Steps

  • MyBatis mapper XML uses #{} exclusively — grep for ${} in src/main/resources/mapper/
  • All JdbcTemplate queries use ? placeholders
  • No string concatenation in SQL
  • No native queries with string interpolation
  • JPQL or Criteria API used for dynamic queries

4. Authentication & Authorization

Spring Security Configuration (stateless JWT REST API)

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            // Stateless JWT APIs do not use server-side sessions → CSRF not applicable
            .csrf(AbstractHttpConfigurer::disable)
            .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/v1/auth/**").permitAll()
                .requestMatchers("/api/v1/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}
// For stateful session-based apps (e.g. admin panel), enable CSRF:
// .csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))

#### Authorization Checks
```java
@PreAuthorize("hasRole('ADMIN') or #userId == authentication.name")
@DeleteMapping("/api/v1/users/{userId}")
public ResponseEntity<Void> deleteUser(@PathVariable String userId) {
    userService.delete(userId);
    return ResponseEntity.noContent().build();
}

Verification Steps

  • JWT tokens validated on every request
  • @PreAuthorize or security filter used for authorization
  • Role-based access control implemented
  • Tokens not logged or exposed in error messages
  • Session management correctly configured (stateless for APIs)

5. XSS Prevention

Sanitize Output in Responses

// If returning user-provided content as HTML, sanitize it
// Use OWASP Java HTML Sanitizer

PolicyFactory policy = Sanitizers.FORMATTING.and(Sanitizers.LINKS);
String safeHtml = policy.sanitize(userProvidedHtml);

Content Security Policy Header

@Component
public class SecurityHeadersFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        response.setHeader("Content-Security-Policy",
            "default-src 'self'; script-src 'self'; img-src 'self' data: https:;");
        response.setHeader("X-Content-Type-Options", "nosniff");
        response.setHeader("X-Frame-Options", "DENY");
        chain.doFilter(request, response);
    }
}

Verification Steps

  • User-provided HTML sanitized before rendering
  • CSP headers configured
  • X-Content-Type-Options: nosniff set
  • X-Frame-Options: DENY set

6. CSRF Protection

// Spring Security CSRF is enabled by default for stateful apps
// For stateless JWT APIs, CSRF is not needed but session fixation must be prevented
http.csrf(AbstractHttpConfigurer::disable)  // Only for stateless JWT APIs
    .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

// For stateful apps (e.g. admin panel with sessions):
http.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));

Verification Steps

  • CSRF enabled for stateful session-based endpoints
  • Stateless JWT APIs have SessionCreationPolicy.STATELESS
  • SameSite cookie attribute set where appropriate

7. Rate Limiting

With Bucket4j (Spring Boot)

@Component
public class RateLimitingFilter extends OncePerRequestFilter {
    private final Map<String, Bucket> cache = new ConcurrentHashMap<>();

    private Bucket createNewBucket() {
        Bandwidth limit = Bandwidth.classic(100, Refill.greedy(100, Duration.ofMinutes(1)));
        return Bucket.builder().addLimit(limit).build();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String ip = request.getRemoteAddr();
        Bucket bucket = cache.computeIfAbsent(ip, k -> createNewBucket());

        if (bucket.tryConsume(1)) {
            chain.doFilter(request, response);
        } else {
            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
            response.getWriter().write("{\"error\":{\"code\":\"rate_limit_exceeded\"}}");
        }
    }
}

Verification Steps

  • Rate limiting on all public API endpoints
  • Stricter limits on expensive operations (search, export)
  • 429 Too Many Requests returned with Retry-After header

8. Sensitive Data Exposure

Logging

// ❌ WRONG: Logging sensitive data
log.info("User login: email={}, password={}", email, password);
log.info("Payment: cardNumber={}, cvv={}", cardNumber, cvv);

// ✅ CORRECT: Redact sensitive data
log.info("User login: email={}, userId={}", email, userId);
log.info("Payment: last4={}, userId={}", card.getLast4(), userId);

Error Messages

// ❌ WRONG: Exposing internal details
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> handleException(Exception e) {
    return ResponseEntity.status(500).body(Map.of(
        "error", e.getMessage(),
        "stackTrace", Arrays.toString(e.getStackTrace())
    ));
}

// ✅ CORRECT: Generic error messages
@ExceptionHandler(Exception.class)
public ResponseEntity<Map<String, Object>> handleException(Exception e) {
    log.error("Internal error", e);
    return ResponseEntity.status(500).body(Map.of(
        "error", Map.of("code", "internal_error",
                        "message", "An error occurred. Please try again.")
    ));
}

Verification Steps

  • No passwords, tokens, or secrets in logs
  • Error messages generic for users
  • Detailed errors only in server logs
  • No stack traces exposed in API responses

9. Dependency Security

Regular Updates

# Check for vulnerabilities (OWASP Dependency Check)
./gradlew dependencyCheckAnalyze

# List outdated dependencies
./gradlew dependencyUpdates

# Check direct dependencies
./gradlew dependencies --configuration runtimeClasspath

Verification Steps

  • OWASP Dependency Check passes with no critical CVEs
  • Dependencies up to date
  • Lock file (gradle.lockfile) committed for reproducible builds
  • Dependabot or Renovate enabled on GitHub

Security Testing

Automated Security Tests (JUnit 5)

// Test authentication required
@Test
void protectedEndpointRequiresAuthentication() throws Exception {
    mockMvc.perform(get("/api/v1/users"))
        .andExpect(status().isUnauthorized());
}

// Test authorization
@Test
@WithMockUser(roles = "USER")
void adminEndpointForbiddenForUser() throws Exception {
    mockMvc.perform(delete("/api/v1/admin/users/123"))
        .andExpect(status().isForbidden());
}

// Test input validation
@Test
void rejectsInvalidEmail() throws Exception {
    String body = """{"email": "not-an-email", "name": "Test"}""";
    mockMvc.perform(post("/api/v1/users")
            .contentType(MediaType.APPLICATION_JSON)
            .content(body))
        .andExpect(status().isBadRequest());
}

Pre-Deployment Security Checklist

Before ANY production deployment:

  • Secrets: No hardcoded secrets, all in env vars or Vault
  • Input Validation: All user inputs validated with @Valid
  • SQL Injection: All queries parameterized or using JPA
  • XSS: User-provided HTML sanitized, CSP headers set
  • CSRF: Protection configured for session-based endpoints
  • Authentication: Spring Security configured correctly
  • Authorization: @PreAuthorize or security filters in place
  • Rate Limiting: Enabled on public endpoints
  • HTTPS: Enforced in production
  • Error Handling: No stack traces or internal details in responses
  • Logging: No sensitive data logged
  • Dependencies: OWASP check passes, no critical CVEs
  • CORS: Properly configured for allowed origins
  • File Uploads: Validated (size, type, path traversal)

Resources


Remember: Security is not optional. One vulnerability can compromise the entire platform. When in doubt, err on the side of caution.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.