Communitygithub.com

perl-security

Seguridad integral para Perl que cubre modo taint, validación de entrada, ejecución segura de procesos, consultas parametrizadas con DBI, seguridad web (XSS/SQLi/CSRF) y políticas de perlcritic. Actívalo al revisar el manejo de entrada, ejecución de procesos, consultas DBI o código web en Perl.

¿Qué es perl-security?

Patrones de Seguridad para Perl es un skill diseñado para guiar a desarrolladores y revisores de código en la aplicación de prácticas de seguridad robustas en aplicaciones Perl. Su objetivo principal es prevenir vulnerabilidades comunes como inyección SQL, cross-site scripting (XSS), command injection y path traversal. El skill se activa automáticamente cuando se detecta manipulación de entrada de usuario, construcción de aplicaciones web (CGI, Mojolicious, Dancer2, Catalyst), revisión de código de seguridad, operaciones de archivos con rutas proporcionadas por el usuario o ejecución de comandos del sistema desde Perl. Proporciona ejemplos concretos de código seguro y patrones a evitar, cubriendo modo taint, validación con listas blancas, operaciones seguras de archivos con open de tres argumentos y File::Temp, ejecución de procesos con system en forma de lista y módulos como IPC::Run3, prevención de inyección SQL mediante placeholders de DBI y manejo de columnas dinámicas con listas blancas, y seguridad web con codificación de salida, protección CSRF y cabeceras de seguridad. También incluye una configuración de perlcritic enfocada en seguridad para automatizar la detección de malas prácticas. El skill promueve el principio de defensa en profundidad, recordando que la flexibilidad de Perl requiere disciplina.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/perl-security

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Patrones de Seguridad para Perl

Guía integral de seguridad para aplicaciones Perl que cubre validación de entrada, prevención de inyección y prácticas de codificación segura.

Cuándo activarlo

  • Al manejar entrada de usuario en aplicaciones Perl
  • Al construir aplicaciones web Perl (CGI, Mojolicious, Dancer2, Catalyst)
  • Al revisar código Perl en busca de vulnerabilidades de seguridad
  • Al realizar operaciones de archivos con rutas proporcionadas por el usuario
  • Al ejecutar comandos del sistema desde Perl
  • Al escribir consultas de base de datos con DBI

Cómo funciona

Comienza con los límites de entrada sensibles a taint, luego avanza hacia afuera: valida y descontamina entradas, mantén el sistema de archivos y la ejecución de procesos bajo control, y usa consultas DBI parametrizadas en todas partes. Los ejemplos a continuación muestran los valores seguros predeterminados que este skill espera que apliques antes de publicar código Perl que toque entrada de usuario, el shell o la red.

Modo Taint

El modo taint de Perl (-T) rastrea los datos de fuentes externas y evita que se utilicen en operaciones inseguras sin validación explícita.

Habilitando el Modo Taint

#!/usr/bin/perl -T
use v5.36;

# Contaminado: cualquier cosa de fuera del programa
my $input    = $ARGV[0];        # Contaminado
my $env_path = $ENV{PATH};      # Contaminado
my $form     = <STDIN>;         # Contaminado
my $query    = $ENV{QUERY_STRING}; # Contaminado

# Sanear PATH desde el principio (requerido en modo taint)
$ENV{PATH} = '/usr/local/bin:/usr/bin:/bin';
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};

Patrón de Descontaminación

use v5.36;

# Bien: Validar y descontaminar con una expresión regular específica
sub descontaminar_usuario($input) {
    if ($input =~ /^([a-zA-Z0-9_]{3,30})$/) {
        return $1;  # $1 está descontaminado
    }
    die "Nombre de usuario inválido: debe tener entre 3 y 30 caracteres alfanuméricos\n";
}

# Bien: Validar y descontaminar una ruta de archivo
sub descontaminar_archivo($input) {
    if ($input =~ m{^([a-zA-Z0-9._-]+)$}) {
        return $1;
    }
    die "Nombre de archivo inválido: contiene caracteres inseguros\n";
}

# Mal: Descontaminación demasiado permisiva (anula el propósito)
sub mala_descontaminacion($input) {
    $input =~ /^(.*)$/s;
    return $1;  # Acepta CUALQUIER COSA — inútil
}

Validación de Entrada

Lista Blanca sobre Lista Negra

use v5.36;

# Bien: Lista blanca — define exactamente lo que está permitido
sub validar_campo_orden($field) {
    my %permitido = map { $_ => 1 } qw(name email created_at updated_at);
    die "Campo de orden inválido: $field\n" unless $permitido{$field};
    return $field;
}

# Bien: Validar con patrones específicos
sub validar_email($email) {
    if ($email =~ /^([a-zA-Z0-9._%+-]+\@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/) {
        return $1;
    }
    die "Dirección de correo inválida\n";
}

sub validar_entero($input) {
    if ($input =~ /^(-?\d{1,10})$/) {
        return $1 + 0;  # Forzar a número
    }
    die "Entero inválido\n";
}

# Mal: Lista negra — siempre incompleta
sub mala_validacion($input) {
    die "Inválido" if $input =~ /[<>"';&|]/;  # Omite ataques codificados
    return $input;
}

Restricciones de Longitud

use v5.36;

sub validar_comentario($text) {
    die "Se requiere comentario\n"        unless length($text) > 0;
    die "El comentario excede los 10000 caracteres\n" if length($text) > 10_000;
    return $text;
}

Expresiones Regulares Seguras

Prevención de ReDoS

El retroceso catastrófico ocurre con cuantificadores anidados en patrones superpuestos.

use v5.36;

# Mal: Vulnerable a ReDoS (retroceso exponencial)
my $re_mal = qr/^(a+)+$/;           # Cuantificadores anidados
my $re_mal2 = qr/^([a-zA-Z]+)*$/;   # Cuantificadores anidados en clase
my $re_mal3 = qr/^(.*?,){10,}$/;    # Combinación repetida greedy/lazy

# Bien: Reescribir sin anidamiento
my $re_bien = qr/^a+$/;             # Cuantificador único
my $re_bien2 = qr/^[a-zA-Z]+$/;     # Cuantificador único en clase

# Bien: Usar cuantificadores posesivos o grupos atómicos para evitar retroceso
my $re_seguro = qr/^[a-zA-Z]++$/;             # Posesivo (5.10+)
my $re_seguro2 = qr/^(?>a+)$/;                # Grupo atómico

# Bien: Forzar tiempo de espera en patrones no confiables
use POSIX qw(alarm);
sub coincidencia_segura($string, $pattern, $timeout = 2) {
    my $coincidio;
    eval {
        local $SIG{ALRM} = sub { die "Tiempo de espera de regex agotado\n" };
        alarm($timeout);
        $coincidio = $string =~ $pattern;
        alarm(0);
    };
    alarm(0);
    die $@ if $@;
    return $coincidio;
}

Operaciones Seguras de Archivos

Open de Tres Argumentos

use v5.36;

# Bien: Open de tres argumentos, manejador de archivo léxico, verificar retorno
sub leer_archivo($path) {
    open my $fh, '<:encoding(UTF-8)', $path
        or die "No se puede abrir '$path': $!\n";
    local $/;
    my $content = <$fh>;
    close $fh;
    return $content;
}

# Mal: Open de dos argumentos con datos de usuario (inyección de comandos)
sub mala_lectura($path) {
    open my $fh, $path;        # Si $path = "|rm -rf /", ¡ejecuta comando!
    open my $fh, "< $path";   # Inyección de metacaracteres de shell
}

Prevención de TOCTOU y Path Traversal

use v5.36;
use Fcntl qw(:DEFAULT :flock);
use File::Spec;
use Cwd qw(realpath);

# Creación atómica de archivos
sub crear_archivo_seguro($path) {
    sysopen(my $fh, $path, O_WRONLY | O_CREAT | O_EXCL, 0600)
        or die "No se puede crear '$path': $!\n";
    return $fh;
}

# Validar que la ruta permanezca dentro del directorio permitido
sub ruta_segura($base_dir, $user_path) {
    my $real = realpath(File::Spec->catfile($base_dir, $user_path))
        // die "La ruta no existe\n";
    my $base_real = realpath($base_dir)
        // die "El directorio base no existe\n";
    die "Path traversal bloqueado\n" unless $real =~ /^\Q$base_real\E(?:\/|\z)/;
    return $real;
}

Usa File::Temp para archivos temporales (tempfile(UNLINK => 1)) y flock(LOCK_EX) para evitar condiciones de carrera.

Ejecución Segura de Procesos

system y exec en Forma de Lista

use v5.36;

# Bien: Forma de lista — sin interpolación de shell
sub ejecutar_comando(@cmd) {
    system(@cmd) == 0
        or die "Comando falló: @cmd\n";
}

ejecutar_comando('grep', '-r', $patron_usuario, '/var/log/app/');

# Bien: Capturar salida de forma segura con IPC::Run3
use IPC::Run3;
sub capturar_salida(@cmd) {
    my ($stdout, $stderr);
    run3(\@cmd, \undef, \$stdout, \$stderr);
    if ($?) {
        die "Comando falló (salida $?): $stderr\n";
    }
    return $stdout;
}

# Mal: Forma de cadena — ¡inyección de shell!
sub busqueda_mala($pattern) {
    system("grep -r '$pattern' /var/log/app/");  # Si $pattern = "'; rm -rf / #"
}

# Mal: Backticks con interpolación
my $output = `ls $directorio_usuario`;   # Riesgo de inyección de shell

También usa Capture::Tiny para capturar stdout/stderr de comandos externos de forma segura.

Prevención de Inyección SQL

Placeholders de DBI

use v5.36;
use DBI;

my $dbh = DBI->connect($dsn, $user, $pass, {
    RaiseError => 1,
    PrintError => 0,
    AutoCommit => 1,
});

# Bien: Consultas parametrizadas — usa siempre placeholders
sub buscar_usuario($dbh, $email) {
    my $sth = $dbh->prepare('SELECT * FROM users WHERE email = ?');
    $sth->execute($email);
    return $sth->fetchrow_hashref;
}

sub buscar_usuarios($dbh, $name, $status) {
    my $sth = $dbh->prepare(
        'SELECT * FROM users WHERE name LIKE ? AND status = ? ORDER BY name'
    );
    $sth->execute("%$name%", $status);
    return $sth->fetchall_arrayref({});
}

# Mal: Interpolación de cadenas en SQL (¡vulnerabilidad SQLi!)
sub mala_busqueda($dbh, $email) {
    my $sth = $dbh->prepare("SELECT * FROM users WHERE email = '$email'");
    # Si $email = "' OR 1=1 --", devuelve todos los usuarios
    $sth->execute;
    return $sth->fetchrow_hashref;
}

Listas Blancas de Columnas Dinámicas

use v5.36;

# Bien: Validar nombres de columna contra una lista blanca
sub order_by($dbh, $column, $direction) {
    my %cols_permitidas = map { $_ => 1 } qw(name email created_at);
    my %dirs_permitidas = map { $_ => 1 } qw(ASC DESC);

    die "Columna inválida: $column\n"    unless $cols_permitidas{$column};
    die "Dirección inválida: $direction\n" unless $dirs_permitidas{uc $direction};

    my $sth = $dbh->prepare("SELECT * FROM users ORDER BY $column $direction");
    $sth->execute;
    return $sth->fetchall_arrayref({});
}

# Mal: Interpolar directamente la columna elegida por el usuario
sub mal_order($dbh, $column) {
    $dbh->prepare("SELECT * FROM users ORDER BY $column");  # SQLi!
}

DBIx::Class (Seguridad con ORM)

use v5.36;

# DBIx::Class genera consultas parametrizadas seguras
my @users = $schema->resultset('User')->search({
    status => 'active',
    email  => { -like => '%@example.com' },
}, {
    order_by => { -asc => 'name' },
    rows     => 50,
});

Seguridad Web

Prevención de XSS

use v5.36;
use HTML::Entities qw(encode_entities);
use URI::Escape qw(uri_escape_utf8);

# Bien: Codificar salida para contexto HTML
sub html_seguro($user_input) {
    return encode_entities($user_input);
}

# Bien: Codificar para contexto URL
sub parametro_url_seguro($value) {
    return uri_escape_utf8($value);
}

# Bien: Codificar para contexto JSON
use JSON::MaybeXS qw(encode_json);
sub json_seguro($data) {
    return encode_json($data);  # Maneja el escape
}

# Auto-escape de plantillas (Mojolicious)
# <%= $user_input %>   — auto-escaped (seguro)
# <%== $raw_html %>    — salida sin escape (peligroso, usar solo para contenido confiable)

# Auto-escape de plantillas (Template Toolkit)
# [% user_input | html %]  — codificación HTML explícita

# Mal: Salida sin procesar en HTML
sub html_malo($input) {
    print "<div>$input</div>";  # XSS si $input contiene <script>
}

Protección CSRF

use v5.36;
use Crypt::URandom qw(urandom);
use MIME::Base64 qw(encode_base64url);

sub generar_token_csrf() {
    return encode_base64url(urandom(32));
}

Utiliza comparación de tiempo constante al verificar tokens. La mayoría de los frameworks web (Mojolicious, Dancer2, Catalyst) proporcionan protección CSRF incorporada — prefiere esas sobre soluciones hechas a mano.

Seguridad de Sesiones y Cabeceras

use v5.36;

# Mojolicious sesión + cabeceras
$app->secrets(['secreto-largo-aleatorio-rotado-regularmente']);
$app->sessions->secure(1);          # Solo HTTPS
$app->sessions->samesite('Lax');

$app->hook(after_dispatch => sub ($c) {
    $c->res->headers->header('X-Content-Type-Options' => 'nosniff');
    $c->res->headers->header('X-Frame-Options'        => 'DENY');
    $c->res->headers->header('Content-Security-Policy' => "default-src 'self'");
    $c->res->headers->header('Strict-Transport-Security' => 'max-age=31536000; includeSubDomains');
});

Codificación de Salida

Siempre codifica la salida según su contexto: HTML::Entities::encode_entities() para HTML, URI::Escape::uri_escape_utf8() para URLs, JSON::MaybeXS::encode_json() para JSON.

Seguridad de Módulos CPAN

  • Fija versiones en cpanfile: requires 'DBI', '== 1.643';
  • Prefiere módulos mantenidos: Revisa MetaCPAN para lanzamientos recientes
  • Minimiza dependencias: Cada dependencia es una superficie de ataque

Herramientas de Seguridad

Políticas de Seguridad de perlcritic

# .perlcriticrc — configuración enfocada en seguridad
severity = 3
theme = security + core

# Requerir open de tres argumentos
[InputOutput::RequireThreeArgOpen]
severity = 5

# Requerir llamadas al sistema verificadas
[InputOutput::RequireCheckedSyscalls]
functions = :builtins
severity = 4

# Prohibir eval de cadenas
[BuiltinFunctions::ProhibitStringyEval]
severity = 5

# Prohibir operadores de backtick
[InputOutput::ProhibitBacktickOperators]
severity = 4

# Requerir verificación de taint en CGI
[Modules::RequireTaintChecking]
severity = 5

# Prohibir open de dos argumentos
[InputOutput::ProhibitTwoArgOpen]
severity = 5

# Prohibir manejadores de archivo sin comillas
[InputOutput::ProhibitBarewordFileHandles]
severity = 5

Ejecutando perlcritic

# Verificar un archivo
perlcritic --severity 3 --theme security lib/MyApp/Handler.pm

# Verificar todo el proyecto
perlcritic --severity 3 --theme security lib/

# Integración CI
perlcritic --severity 4 --theme security --quiet lib/ || exit 1

Lista de Verificación Rápida de Seguridad

VerificaciónQué Comprobar
Modo TaintBandera -T en scripts CGI/web
Validación de entradaPatrones de lista blanca, límites de longitud
Operaciones de archivosOpen de tres argumentos, comprobaciones de path traversal
Ejecución de procesossystem en forma de lista, sin interpolación de shell
Consultas SQLPlaceholders de DBI, nunca interpolar
Salida HTMLencode_entities(), auto-escape de plantillas
Tokens CSRFGenerados, verificados en solicitudes que cambian el estado
Configuración de sesiónCookies Secure, HttpOnly, SameSite
Cabeceras HTTPCSP, X-Frame-Options, HSTS
DependenciasVersiones fijas, módulos auditados
Seguridad de regexSin cuantificadores anidados, patrones anclados
Mensajes de errorSin rastros de pila ni rutas filtradas a los usuarios

Anti-Patrones

# 1. Open de dos argumentos con datos de usuario (inyección de comandos)
open my $fh, $user_input;               # Vulnerabilidad CRÍTICA

# 2. system en forma de cadena (inyección de shell)
system("convert $user_file output.png"); # Vulnerabilidad CRÍTICA

# 3. Interpolación de cadenas en SQL
$dbh->do("DELETE FROM users WHERE id = $id");  # SQLi

# 4. eval con entrada de usuario (inyección de código)
eval $user_code;                         # Ejecución remota de código

# 5. Confiar en $ENV sin sanear
my $path = $ENV{UPLOAD_DIR};             # Podría ser manipulado
system("ls $path");                      # Doble vulnerabilidad

# 6. Deshabilitar taint sin validación
($input) = $input =~ /(.*)/s;           # Descontaminación perezosa — anula el propósito

# 7. Datos de usuario sin procesar en HTML
print "<div>Welcome, $username!</div>";  # XSS

# 8. Redirecciones no validadas
print $cgi->redirect($url_usuario);         # Redirección abierta

Recuerda: La flexibilidad de Perl es poderosa pero requiere disciplina. Usa el modo taint para código orientado a la web, valida toda la entrada con listas blancas, usa placeholders de DBI para cada consulta y codifica toda la salida según su contexto. Defensa en profundidad — nunca confíes en una sola capa.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Skills relacionados