Agent skill

Input Validation

by Hack23 in Hack23/cia

Implement comprehensive input validation to prevent XSS, SQL injection, and command injection attacks with sanitization strategies

Apache-2.0Auto-check passedSecurity

Install Input Validation

skills CLI
$ npx skills add Hack23/cia --skill input-validation -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install Hack23/cia input-validation --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/Hack23/cia.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.github/skills/input-validation .claude/skills/input-validation && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
input-validation
GitHub stars
239
Token cost
~5.9k tokens
SKILL.md length
436 words
Files
1
Skills in repo
78
Repo updated
First seen
Licence
Apache-2.0

At a glance

Implement comprehensive input validation to prevent XSS, SQL injection, and command injection attacks with sanitization strategies

  • Tasks that involve Web application vulnerabilities
  • SKILL.md covers Purpose, When to Use This Skill, Validation Principles and Input Validation Patterns, plus 6 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Input Validation is an agent skill from Hack23/cia. Implement comprehensive input validation to prevent XSS, SQL injection, and command injection attacks with sanitization strategies

Its SKILL.md is about 5.9k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Security, covering Web application vulnerabilities. The repository describes itself as: Citizen Intelligence Agency. Open-source intelligence platform analyzing Swedish political activities using AI and data visualization. Tracks politicians, government… The licence is Apache-2.0.

When your agent uses it

  • Tasks that involve Web application vulnerabilities

Example prompts

  • “/input-validation”

What it can do on your machine

Read from SKILL.md and the folder at commit 6a9797b. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are java).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • github.com
    • cheatsheetseries.owasp.org
    • owasp.org
    • beanvalidation.org

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Input Validation loads about 5.9k tokens when it runs. Until then it costs about 37 tokens; SKILL.md has 436 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~37
When it runs · the whole SKILL.md, loaded when a task matches
~5.9k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from Hack23/cia at commit 6a9797b, republished under its Apache-2.0 licence (© Hack23). 436 words, ~5,870 tokens.

Download SKILL.mdSave it as .claude/skills/input-validation/SKILL.md (or your agent's skills folder).
name
input-validation
description
Implement comprehensive input validation to prevent XSS, SQL injection, and command injection attacks with sanitization strategies
license
Apache-2.0

Input Validation Skill

Purpose

This skill provides systematic approaches to validate, sanitize, and encode all user inputs to prevent injection attacks, XSS, and data corruption. It implements defense-in-depth validation at multiple layers aligned with OWASP best practices and Hack23 ISMS secure coding standards.

When to Use This Skill

Apply this skill when:

  • ✅ Processing any user-provided input (forms, APIs, URL parameters)
  • ✅ Handling data from external systems (Riksdagen API, World Bank)
  • ✅ Constructing database queries or commands
  • ✅ Rendering user-generated content in UI
  • ✅ Processing file uploads
  • ✅ Implementing search functionality
  • ✅ Building dynamic SQL, LDAP, or OS commands

Validation Principles

Principle #1: Validate Early, Validate Often

Multi-Layer Validation:

Client Side (JavaScript)  → Basic UX validation
    ↓
Server Side (Controller)  → Format and type validation
    ↓
Service Layer            → Business logic validation
    ↓
Database Layer           → Constraint enforcement
Principle #2: Allowlist Over Blocklist

❌ INSECURE - Blocklist Approach:

java
// BAD: Trying to block malicious patterns (incomplete, bypassable)
public boolean isValidInput(String input) {
    String[] badPatterns = {"<script>", "javascript:", "onerror=", "' OR '1'='1"};
    for (String pattern : badPatterns) {
        if (input.toLowerCase().contains(pattern)) {
            return false;
        }
    }
    return true;
}

✅ SECURE - Allowlist Approach:

java
// GOOD: Define what IS valid
public boolean isValidPoliticianName(String name) {
    // Only allow letters, spaces, hyphens, and apostrophes
    return name != null && 
           name.matches("^[A-Za-zÀ-ÿ\\s'-]{2,50}$") &&
           name.length() >= 2 &&
           name.length() <= 50;
}

public boolean isValidEmail(String email) {
    // Use standard email regex
    String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
    return email != null && email.matches(emailRegex);
}

public boolean isValidYear(Integer year) {
    // Define valid range
    int currentYear = Year.now().getValue();
    return year != null && 
           year >= 1900 && 
           year <= currentYear;
}
Principle #3: Fail Securely
java
@ControllerAdvice
public class ValidationExceptionHandler {
    
    private static final Logger log = LoggerFactory.getLogger(ValidationExceptionHandler.class);
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationException(
            MethodArgumentNotValidException ex) {
        
        // Log detailed error for debugging (but don't expose to user)
        log.warn("Validation failed: {}", ex.getBindingResult().getAllErrors());
        
        // Return generic error to user (don't leak validation logic)
        ErrorResponse error = new ErrorResponse(
            "Invalid input",
            "One or more fields contain invalid data"
        );
        
        return ResponseEntity.badRequest().body(error);
    }
    
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<ErrorResponse> handleConstraintViolation(
            ConstraintViolationException ex) {
        
        log.warn("Constraint violation: {}", ex.getMessage());
        
        ErrorResponse error = new ErrorResponse(
            "Invalid input",
            "The provided data does not meet requirements"
        );
        
        return ResponseEntity.badRequest().body(error);
    }
}

Input Validation Patterns

Pattern #1: Bean Validation (JSR-380)
java
// Domain model with validation constraints
@Entity
@Table(name = "politician")
public class Politician {
    
    @Id
    @NotNull
    @Pattern(regexp = "^[0-9]{12}$", message = "Personal ID must be 12 digits")
    private String personalId;
    
    @NotBlank(message = "First name is required")
    @Size(min = 2, max = 50, message = "First name must be 2-50 characters")
    @Pattern(regexp = "^[A-Za-zÀ-ÿ\\s'-]+$", message = "First name contains invalid characters")
    private String firstName;
    
    @NotBlank(message = "Last name is required")
    @Size(min = 2, max = 50, message = "Last name must be 2-50 characters")
    @Pattern(regexp = "^[A-Za-zÀ-ÿ\\s'-]+$", message = "Last name contains invalid characters")
    private String lastName;
    
    @NotNull(message = "Birth date is required")
    @Past(message = "Birth date must be in the past")
    private LocalDate birthDate;
    
    @Email(message = "Invalid email format")
    @Pattern(regexp = "^[A-Za-z0-9+_.-]+@riksdagen\\.se$", 
             message = "Only riksdagen.se emails allowed")
    private String officialEmail;
    
    @Pattern(regexp = "^\\+46[0-9]{9}$", message = "Invalid Swedish phone number")
    private String phoneNumber;
    
    @NotNull(message = "Party is required")
    @Enumerated(EnumType.STRING)
    private PoliticalParty party;
}

// DTO for API requests
public class CreatePoliticianRequest {
    
    @NotBlank
    @Size(min = 2, max = 50)
    @Pattern(regexp = "^[A-Za-zÀ-ÿ\\s'-]+$")
    private String firstName;
    
    @NotBlank
    @Size(min = 2, max = 50)
    @Pattern(regexp = "^[A-Za-zÀ-ÿ\\s'-]+$")
    private String lastName;
    
    @NotNull
    @Past
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate birthDate;
    
    @Email
    private String email;
    
    @Pattern(regexp = "^\\+46[0-9]{9}$")
    private String phoneNumber;
    
    @NotNull
    private String partyCode;
    
    // Getters and setters
}

// Controller with validation
@RestController
@RequestMapping("/api/politicians")
@Validated
public class PoliticianController {
    
    @PostMapping
    public ResponseEntity<Politician> createPolitician(
            @Valid @RequestBody CreatePoliticianRequest request) {
        
        // If validation passes, create politician
        Politician politician = politicianService.create(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(politician);
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<Politician> getPolitician(
            @PathVariable 
            @Pattern(regexp = "^[0-9]{12}$", message = "Invalid politician ID") 
            String id) {
        
        Politician politician = politicianService.findById(id)
            .orElseThrow(() -> new ResourceNotFoundException("Politician not found"));
        
        return ResponseEntity.ok(politician);
    }
}
Pattern #2: Custom Validators
java
// Custom annotation for Swedish Personal ID
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = SwedishPersonalIdValidator.class)
public @interface ValidSwedishPersonalId {
    String message() default "Invalid Swedish personal ID";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

// Validator implementation with checksum
public class SwedishPersonalIdValidator implements ConstraintValidator<ValidSwedishPersonalId, String> {
    
    @Override
    public boolean isValid(String personalId, ConstraintValidatorContext context) {
        if (personalId == null || personalId.length() != 12) {
            return false;
        }
        
        // Check format: YYYYMMDDNNNN
        if (!personalId.matches("^[0-9]{12}$")) {
            return false;
        }
        
        // Validate date part
        try {
            int year = Integer.parseInt(personalId.substring(0, 4));
            int month = Integer.parseInt(personalId.substring(4, 6));
            int day = Integer.parseInt(personalId.substring(6, 8));
            
            LocalDate.of(year, month, day);
        } catch (DateTimeException e) {
            return false;
        }
        
        // Validate Luhn checksum
        return validateLuhnChecksum(personalId);
    }
    
    private boolean validateLuhnChecksum(String number) {
        int sum = 0;
        boolean alternate = false;
        
        for (int i = number.length() - 1; i >= 0; i--) {
            int digit = Character.getNumericValue(number.charAt(i));
            
            if (alternate) {
                digit *= 2;
                if (digit > 9) {
                    digit = (digit % 10) + 1;
                }
            }
            
            sum += digit;
            alternate = !alternate;
        }
        
        return (sum % 10 == 0);
    }
}

// Usage
@Entity
public class Politician {
    @Id
    @ValidSwedishPersonalId
    private String personalId;
}
Pattern #3: Sanitization for XSS Prevention
java
@Component
public class InputSanitizer {
    
    private final Policy antiSamyPolicy;
    
    public InputSanitizer() throws PolicyException {
        // Load OWASP AntiSamy policy
        this.antiSamyPolicy = Policy.getInstance(
            getClass().getResourceAsStream("/antisamy-policy.xml")
        );
    }
    
    /**
     * Sanitize HTML input to prevent XSS
     */
    public String sanitizeHtml(String input) {
        if (input == null) return null;
        
        try {
            AntiSamy antiSamy = new AntiSamy();
            CleanResults results = antiSamy.scan(input, antiSamyPolicy);
            
            if (results.getNumberOfErrors() > 0) {
                log.warn("Sanitized HTML input. Errors: {}", 
                    results.getErrorMessages());
            }
            
            return results.getCleanHTML();
        } catch (Exception e) {
            log.error("Error sanitizing HTML", e);
            // Fail securely - return empty string
            return "";
        }
    }
    
    /**
     * Encode for HTML output
     */
    public String encodeForHtml(String input) {
        if (input == null) return null;
        return StringEscapeUtils.escapeHtml4(input);
    }
    
    /**
     * Encode for JavaScript output
     */
    public String encodeForJavaScript(String input) {
        if (input == null) return null;
        return StringEscapeUtils.escapeEcmaScript(input);
    }
    
    /**
     * Encode for URL parameter
     */
    public String encodeForUrl(String input) {
        if (input == null) return null;
        try {
            return URLEncoder.encode(input, StandardCharsets.UTF_8);
        } catch (Exception e) {
            return "";
        }
    }
    
    /**
     * Remove all non-alphanumeric characters
     */
    public String alphanumericOnly(String input) {
        if (input == null) return null;
        return input.replaceAll("[^A-Za-z0-9]", "");
    }
    
    /**
     * Truncate to maximum length
     */
    public String truncate(String input, int maxLength) {
        if (input == null) return null;
        if (input.length() <= maxLength) return input;
        return input.substring(0, maxLength);
    }
}

// Usage in service layer
@Service
public class CommentService {
    
    @Autowired
    private InputSanitizer sanitizer;
    
    public Comment createComment(String authorId, String content) {
        // Sanitize user-generated content
        String sanitizedContent = sanitizer.sanitizeHtml(content);
        
        // Truncate to reasonable length
        sanitizedContent = sanitizer.truncate(sanitizedContent, 5000);
        
        Comment comment = new Comment();
        comment.setAuthorId(authorId);
        comment.setContent(sanitizedContent);
        comment.setCreatedAt(Instant.now());
        
        return commentRepository.save(comment);
    }
}

// Usage in Vaadin UI
@Component
public class CommentView extends VerticalLayout {
    
    @Autowired
    private InputSanitizer sanitizer;
    
    public void displayComment(Comment comment) {
        // Encode for HTML display
        String safeContent = sanitizer.encodeForHtml(comment.getContent());
        
        Html contentHtml = new Html("<div>" + safeContent + "</div>");
        add(contentHtml);
    }
}
Pattern #4: SQL Injection Prevention

✅ SECURE - Parameterized Queries:

java
@Repository
public interface PoliticianRepository extends JpaRepository<Politician, String> {
    
    // JPA Query with named parameters (SAFE)
    @Query("SELECT p FROM Politician p WHERE " +
           "LOWER(p.firstName) LIKE LOWER(CONCAT('%', :searchTerm, '%')) OR " +
           "LOWER(p.lastName) LIKE LOWER(CONCAT('%', :searchTerm, '%'))")
    List<Politician> search(@Param("searchTerm") String searchTerm);
    
    // Spring Data query methods (SAFE)
    List<Politician> findByPartyAndDistrictOrderByLastNameAsc(String party, String district);
}

// Criteria API for dynamic queries (SAFE)
@Repository
public class PoliticianSearchRepository {
    
    @PersistenceContext
    private EntityManager entityManager;
    
    public List<Politician> advancedSearch(PoliticianSearchCriteria criteria) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Politician> query = cb.createQuery(Politician.class);
        Root<Politician> politician = query.from(Politician.class);
        
        List<Predicate> predicates = new ArrayList<>();
        
        // Safe parameter binding
        if (criteria.getFirstName() != null) {
            predicates.add(cb.like(
                cb.lower(politician.get("firstName")),
                "%" + criteria.getFirstName().toLowerCase() + "%"
            ));
        }
        
        if (criteria.getParty() != null) {
            predicates.add(cb.equal(politician.get("party"), criteria.getParty()));
        }
        
        if (criteria.getMinBirthYear() != null) {
            predicates.add(cb.greaterThanOrEqualTo(
                politician.get("birthDate"),
                LocalDate.of(criteria.getMinBirthYear(), 1, 1)
            ));
        }
        
        query.where(predicates.toArray(new Predicate[0]));
        query.orderBy(cb.asc(politician.get("lastName")));
        
        return entityManager.createQuery(query).getResultList();
    }
}

❌ INSECURE - String Concatenation:

java
// NEVER DO THIS!
public List<Politician> searchUnsafe(String searchTerm) {
    String sql = "SELECT * FROM politician WHERE " +
                 "first_name LIKE '%" + searchTerm + "%'";  // SQL INJECTION!
    
    return jdbcTemplate.query(sql, new PoliticianRowMapper());
}
Pattern #5: File Upload Validation
java
@Configuration
public class FileUploadConfig {
    
    private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
    private static final Set<String> ALLOWED_EXTENSIONS = Set.of("jpg", "jpeg", "png", "pdf");
    private static final Set<String> ALLOWED_MIME_TYPES = Set.of(
        "image/jpeg", "image/png", "application/pdf"
    );
    
    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setMaxFileSize(DataSize.ofBytes(MAX_FILE_SIZE));
        factory.setMaxRequestSize(DataSize.ofBytes(MAX_FILE_SIZE));
        return factory.createMultipartConfig();
    }
}

@Service
public class FileValidationService {
    
    private static final Logger log = LoggerFactory.getLogger(FileValidationService.class);
    private static final Set<String> ALLOWED_EXTENSIONS = Set.of("jpg", "jpeg", "png", "pdf");
    private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
    
    /**
     * Comprehensive file validation
     */
    public void validateFile(MultipartFile file) throws ValidationException {
        if (file == null || file.isEmpty()) {
            throw new ValidationException("File is required");
        }
        
        // 1. Check file size
        if (file.getSize() > MAX_FILE_SIZE) {
            throw new ValidationException("File size exceeds maximum of 10 MB");
        }
        
        // 2. Validate filename
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.contains("..")) {
            throw new ValidationException("Invalid filename");
        }
        
        // 3. Check file extension
        String extension = getFileExtension(originalFilename).toLowerCase();
        if (!ALLOWED_EXTENSIONS.contains(extension)) {
            throw new ValidationException(
                "File type not allowed. Allowed types: " + ALLOWED_EXTENSIONS);
        }
        
        // 4. Verify MIME type from content (not just filename)
        try {
            String contentType = detectContentType(file.getInputStream());
            if (!isAllowedContentType(contentType)) {
                throw new ValidationException("File content type not allowed");
            }
        } catch (IOException e) {
            throw new ValidationException("Error reading file");
        }
        
        // 5. Scan for malware (if applicable)
        scanForMalware(file);
    }
    
    private String getFileExtension(String filename) {
        int lastDot = filename.lastIndexOf('.');
        if (lastDot == -1) return "";
        return filename.substring(lastDot + 1);
    }
    
    private String detectContentType(InputStream inputStream) throws IOException {
        return URLConnection.guessContentTypeFromStream(inputStream);
    }
    
    private boolean isAllowedContentType(String contentType) {
        Set<String> allowed = Set.of("image/jpeg", "image/png", "application/pdf");
        return contentType != null && allowed.contains(contentType);
    }
    
    private void scanForMalware(MultipartFile file) {
        // Integrate with malware scanning service if available
        // E.g., ClamAV, VirusTotal API
    }
    
    /**
     * Generate safe filename
     */
    public String generateSafeFilename(String originalFilename) {
        String extension = getFileExtension(originalFilename);
        String uuid = UUID.randomUUID().toString();
        return uuid + "." + extension;
    }
}

@RestController
@RequestMapping("/api/uploads")
public class FileUploadController {
    
    @Autowired
    private FileValidationService fileValidationService;
    
    @PostMapping("/politician-photo")
    public ResponseEntity<UploadResponse> uploadPhoto(
            @RequestParam("file") MultipartFile file,
            @RequestParam("politicianId") @Pattern(regexp = "^[0-9]{12}$") String politicianId) {
        
        // Validate file
        fileValidationService.validateFile(file);
        
        // Generate safe filename
        String safeFilename = fileValidationService.generateSafeFilename(
            file.getOriginalFilename()
        );
        
        // Store file securely
        Path uploadPath = Paths.get("/secure/uploads/photos/", safeFilename);
        Files.copy(file.getInputStream(), uploadPath, StandardCopyOption.REPLACE_EXISTING);
        
        // Update database
        politicianService.updatePhoto(politicianId, safeFilename);
        
        UploadResponse response = new UploadResponse(safeFilename, file.getSize());
        return ResponseEntity.ok(response);
    }
}

Context-Specific Encoding

HTML Context
java
// Vaadin/Thymeleaf - Automatic escaping
<div th:text="${politician.firstName}"></div>  <!-- Auto-escaped -->

// Manual encoding when needed
String safe = StringEscapeUtils.escapeHtml4(userInput);
JavaScript Context
java
// In Vaadin or JavaScript
String safeJs = StringEscapeUtils.escapeEcmaScript(userInput);
String json = objectMapper.writeValueAsString(data); // Proper JSON encoding
URL Context
java
// URL parameters
String safeUrl = URLEncoder.encode(searchTerm, StandardCharsets.UTF_8);
String url = "/search?q=" + safeUrl;
SQL Context
java
// ALWAYS use parameterized queries (covered earlier)
// NEVER build SQL strings with user input

Input Validation Checklist

Before deploying code that processes user input:

Data Type Validation:

  • ✅ Verify data type (string, int, date, etc.)
  • ✅ Check for null/empty values
  • ✅ Validate length constraints
  • ✅ Ensure proper encoding (UTF-8)

Format Validation:

  • ✅ Use regex for pattern matching
  • ✅ Validate against allowlist of acceptable values
  • ✅ Check date/time formats
  • ✅ Verify email/phone formats

Business Logic Validation:

  • ✅ Check value ranges (min/max)
  • ✅ Validate relationships between fields
  • ✅ Verify uniqueness constraints
  • ✅ Ensure data consistency

Security Validation:

  • ✅ Sanitize HTML content (XSS prevention)
  • ✅ Use parameterized queries (SQL injection prevention)
  • ✅ Validate file uploads (type, size, content)
  • ✅ Check for path traversal attempts
  • ✅ Prevent command injection

Output Encoding:

  • ✅ Encode for HTML context
  • ✅ Encode for JavaScript context
  • ✅ Encode for URL context
  • ✅ Encode for CSS context
Show full SKILL.md (163 more words)Show less

ISMS Compliance Mapping

ISO 27001:2022 Controls
  • A.8.28 - Secure Coding: Input validation as secure coding practice
  • A.14.2.1 - Secure Development Policy: Validation requirements
  • A.8.7 - Protection Against Malware: File upload validation
NIST Cybersecurity Framework
  • PR.DS-5: Protections against data leaks implemented
  • DE.CM-4: Malicious input detected
CIS Controls v8
  • Control 16.11: Establish input validation processes
  • Control 18.5: Validate application input

Hack23 ISMS Policy References

Input Validation & Secure Coding Framework:

All Hack23 ISMS Policies: https://github.com/Hack23/ISMS-PUBLIC

CIA Platform Architecture References

References

Standards & Guidelines
Tools & Libraries

© Hack23, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .github/skills/input-validation of Hack23/cia.

Open the folder on GitHubat commit 6a9797b

Compare with similar skills

Input Validation next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Input Validation compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Input Validation this skillHack23/cia239—~5.9kAutomated safety check: PassApache-2.0
Security And Hardeningpenpot/penpot61k6 repos~4.7kAutomated safety check: NotesMPL-2.0
Security Auditoreigent-ai/eigent15k—~1.8kAutomated safety check: NotesApache-2.0
Security Reviewjewbetcha/opentrace11617 repos~3.1kAutomated safety check: NotesMIT
Strix Code Vulnerability Scanusestrix/strix67k—~1.1kAutomated safety check: PassApache-2.0
Code Audit3stoneBrother/code-audit8931 repos~2.7kAutomated safety check: PassNone

Similar skills

  • Hardens code against vulnerabilities. An agent skill from penpot/penpot.

    61k GitHub starsUsed in 6 repos~4.7k tokens
    SecurityAuto-check: notes
  • Security Auditor

    eigent-ai/eigent

    Audits source code, dependencies and config files for vulnerabilities and hardcoded secrets, using two bundled Python scanners and an OWASP Top 10 checklist.

    15k GitHub stars~1.8k tokensUpdated yesterday
    SecurityAuto-check: notes
  • Security Review

    jewbetcha/opentrace

    A skill your agent uses when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment/sensitive features.

    116 GitHub starsUsed in 17 repos~3.1k tokens
    SecurityAuto-check: notes
  • Runs a Strix white-box security review that reads the source, then exploits what it finds in a sandbox so each reported issue has a proof-of-concept.

    67k GitHub stars~1.1k tokensUpdated yesterday
    SecurityAuto-check passed
  • Code Audit

    3stoneBrother/code-audit

    Professional code security audit skill covering 55+ vulnerability types.

    893 GitHub starsUsed in 1 repo~2.7k tokens
    SecurityAuto-check passed
  • Triages findings from a Strix pentest by severity, fixes each root cause with a minimal change, and re-runs Strix to confirm the exploit no longer works.

    67k GitHub stars~1.5k tokensUpdated yesterday
    SecurityAuto-check passed

More from Hack23/cia

All 78 skills in this repo
  • WCAG 2.1 AA compliance, ARIA attributes, keyboard navigation, screen reader optimization for accessible political data platforms

    239 GitHub stars~2.7k tokensUpdated yesterday
    Auto-check passed
  • Advanced chart types, D3.js/Vaadin Charts patterns, political data visualization, time series analysis

    239 GitHub stars~1.5k tokensUpdated yesterday
    Auto-check passed
  • AI Governance

    Hack23/cia

    AI governance, EU AI Act compliance, OWASP LLM security, responsible AI practices for GitHub Copilot agents

    239 GitHub stars~1.4k tokensUpdated yesterday
    Auto-check passed
  • API Integration

    Hack23/cia

    External API integration patterns, retry logic, circuit breakers, caching, rate limiting for government data APIs

    239 GitHub stars~1.9k tokensUpdated yesterday
    Auto-check passed
  • AWS CloudWatch metrics, alarms, dashboards, log insights, and application monitoring for the CIA platform

    239 GitHub stars~1.9k tokensUpdated yesterday
    Auto-check passed
  • AWS security best practices, VPC security, IAM, KMS, CloudTrail, GuardDuty for CIA platform deployment

    239 GitHub stars~2.3k tokensUpdated yesterday
    Auto-check passed

Categories

Questions about Input Validation

What does Input Validation do?

Implement comprehensive input validation to prevent XSS, SQL injection, and command injection attacks with sanitization strategies. Input Validation is an agent skill from Hack23/cia.

When should I use Input Validation?

Input Validation fits situations like: tasks that involve Web application vulnerabilities.

How do I install Input Validation in Claude Code?

Run `npx skills add Hack23/cia --skill input-validation -a claude-code`. Or copy the skill folder (.github/skills/input-validation in Hack23/cia) into .claude/skills/input-validation in your project. Claude Code loads it when a task matches its description.

How do I install Input Validation in Codex?

Run `npx skills add Hack23/cia --skill input-validation -a codex`. Or copy the skill folder (.github/skills/input-validation in Hack23/cia) into .agents/skills/input-validation in your project. Codex loads it when a task matches its description.

Can I use Input Validation in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add Hack23/cia --skill input-validation -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/input-validation, .gemini/skills/input-validation, .github/skills/input-validation and .opencode/skills/input-validation in your project.

What does Input Validation need to run?

SKILL.md names no scripts, command-line tools or credentials: Input Validation is instructions for the agent only.

Does Input Validation access the network?

SKILL.md names 4 domains. As links in the text: github.com, cheatsheetseries.owasp.org, owasp.org and beanvalidation.org. This is read from the text; nothing was executed.

Is Input Validation safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Input Validation use?

Input Validation is published under the Apache-2.0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Input Validation use?

About 5.9k tokens (SKILL.md is roughly 23k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Input Validation?

Skills that share tags, products or a category with Input Validation: Security And Hardening (penpot/penpot, 61k stars), Security Auditor (eigent-ai/eigent, 15k stars), Security Review (jewbetcha/opentrace, 116 stars) and Strix Code Vulnerability Scan (usestrix/strix, 67k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Input Validation?

Hack23 (a GitHub organization) maintains it in Hack23/cia, which has 239 GitHub stars. The repository holds 78 skills in this directory. The repository was last updated on October 6, 2026.

Source: Hack23/cia on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.