Communitygithub.com

perl-security

Sécurité Perl complète : mode taint, validation d’entrée, exécution sécurisée de processus, requêtes paramétrées DBI, sécurité web (XSS/SQLi/CSRF) et politiques perlcritic. À activer lors de la revue de code Perl manipulant des entrées, l’exécution de processus, les requêtes DBI ou le code web.

Qu'est-ce que perl-security ?

La compétence perl-security fournit un guide exhaustif de sécurité pour les applications Perl, couvrant le mode taint, la validation d’entrée par liste blanche, la prévention des injections SQL via les paramètres DBI, la sécurité web (XSS/CSRF), et l’exécution sécurisée de processus. Elle s’appuie sur des exemples concrets montrant les bonnes pratiques (ouverture à trois arguments, list-form system, expressions régulières sûres contre ReDoS) et les anti-patrons à éviter (interpolation de chaîne, eval sur entrée utilisateur, désinfection trop permissive). Elle recommande des outils comme perlcritic avec une configuration orientée sécurité, et insiste sur une approche de défense en profondeur. Cette compétence s’applique aux frameworks web Perl (CGI, Mojolicious, Dancer2, Catalyst) et à tout code Perl manipulant des données externes, des fichiers, des commandes système ou des bases de données.

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

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Modèles de Sécurité Perl

Guide complet de sécurité pour applications Perl : validation d’entrée, prévention d’injection et bonnes pratiques de codage sécurisé.

Quand Activer

  • Traitement d’entrées utilisateur dans des applications Perl
  • Développement d’applications web Perl (CGI, Mojolicious, Dancer2, Catalyst)
  • Revue de code Perl pour détecter des vulnérabilités de sécurité
  • Opérations sur fichiers avec des chemins fournis par l’utilisateur
  • Exécution de commandes système depuis Perl
  • Écriture de requêtes DBI vers une base de données

Fonctionnement

Commencez par les frontières d’entrée sensibles au taint, puis élargissez : validez et désinfectez les entrées, maintenez le système de fichiers et l’exécution de processus sous contrôle, et utilisez des requêtes DBI paramétrées partout. Les exemples ci-dessous montrent les valeurs par défaut sécurisées que cette compétence attend avant de déployer du code Perl qui touche aux entrées utilisateur, au shell ou au réseau.

Mode Taint

Le mode taint de Perl (-T) trace les données provenant de sources externes et empêche leur utilisation dans des opérations dangereuses sans validation explicite.

Activation du Mode Taint

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

# Tainté : tout ce qui vient de l’extérieur du programme
my $input    = $ARGV[0];        # Tainté
my $env_path = $ENV{PATH};      # Tainté
my $form     = <STDIN>;         # Tainté
my $query    = $ENV{QUERY_STRING}; # Tainté

# Désinfecter PATH tôt (obligatoire en mode taint)
$ENV{PATH} = '/usr/local/bin:/usr/bin:/bin';
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};

Modèle de Désinfection (Untainting)

use v5.36;

# Bon : Valider et désinfecter avec une regex spécifique
sub untaint_username($input) {
    if ($input =~ /^([a-zA-Z0-9_]{3,30})$/) {
        return $1;  # $1 n’est plus tainté
    }
    die "Nom d’utilisateur invalide : 3-30 caractères alphanumériques\n";
}

# Bon : Valider et désinfecter un chemin de fichier
sub untaint_filename($input) {
    if ($input =~ m{^([a-zA-Z0-9._-]+)$}) {
        return $1;
    }
    die "Nom de fichier invalide : caractères non autorisés\n";
}

# Mauvais : Désinfection trop permissive (contre-productive)
sub bad_untaint($input) {
    $input =~ /^(.*)$/s;
    return $1;  # Accepte N’IMPORTE QUOI — inutile
}

Validation d’Entrée

Liste Blanche Plutôt que Liste Noire

use v5.36;

# Bon : Liste blanche — définir précisément ce qui est autorisé
sub validate_sort_field($field) {
    my %allowed = map { $_ => 1 } qw(name email created_at updated_at);
    die "Champ de tri invalide : $field\n" unless $allowed{$field};
    return $field;
}

# Bon : Valider avec des motifs spécifiques
sub validate_email($email) {
    if ($email =~ /^([a-zA-Z0-9._%+-]+\@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/) {
        return $1;
    }
    die "Adresse email invalide\n";
}

sub validate_integer($input) {
    if ($input =~ /^(-?\d{1,10})$/) {
        return $1 + 0;  # Convertir en nombre
    }
    die "Entier invalide\n";
}

# Mauvais : Liste noire — toujours incomplète
sub bad_validate($input) {
    die "Invalide" if $input =~ /[<>"';&|]/;  # Rate les attaques encodées
    return $input;
}

Contraintes de Longueur

use v5.36;

sub validate_comment($text) {
    die "Commentaire requis\n"        unless length($text) > 0;
    die "Commentaire dépasse 10 000 caractères\n" if length($text) > 10_000;
    return $text;
}

Expressions Régulières Sûres

Prévention ReDoS

Le backtracking catastrophique survient avec des quantificateurs imbriqués sur des motifs se chevauchant.

use v5.36;

# Mauvais : Vulnérable à ReDoS (backtracking exponentiel)
my $bad_re = qr/^(a+)+$/;           # Quantificateurs imbriqués
my $bad_re2 = qr/^([a-zA-Z]+)$/;    # Quantificateurs imbriqués sur classe
my $bad_re3 = qr/^(.*?,){10,}$/;    # Combinaison glouton/paresseux répétée

# Bon : Réécrire sans imbrication
my $good_re = qr/^a+$/;             # Quantificateur unique
my $good_re2 = qr/^[a-zA-Z]+$/;     # Quantificateur unique sur classe

# Bon : Utiliser des quantificateurs possessifs ou des groupes atomiques pour empêcher le backtracking
my $safe_re = qr/^[a-zA-Z]++$/;             # Possessif (5.10+)
my $safe_re2 = qr/^(?>a+)$/;                # Groupe atomique

# Bon : Forcer un délai d’attente sur les motifs non fiables
use POSIX qw(alarm);
sub safe_match($string, $pattern, $timeout = 2) {
    my $matched;
    eval {
        local $SIG{ALRM} = sub { die "Délai regex dépassé\n" };
        alarm($timeout);
        $matched = $string =~ $pattern;
        alarm(0);
    };
    alarm(0);
    die $@ if $@;
    return $matched;
}

Opérations Fichiers Sûres

Ouverture à Trois Arguments

use v5.36;

# Bon : Ouverture à trois arguments, handle lexical, vérifier le retour
sub read_file($path) {
    open my $fh, '<:encoding(UTF-8)', $path
        or die "Impossible d’ouvrir '$path' : $!\n";
    local $/;
    my $content = <$fh>;
    close $fh;
    return $content;
}

# Mauvais : Ouverture à deux arguments avec données utilisateur (injection de commande)
sub bad_read($path) {
    open my $fh, $path;        # Si $path = "|rm -rf /", exécute une commande !
    open my $fh, "< $path";   # Injection de métacaractères shell
}

Prévention TOCTOU et Parcours de Chemin

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

# Création atomique de fichier
sub create_file_safe($path) {
    sysopen(my $fh, $path, O_WRONLY | O_CREAT | O_EXCL, 0600)
        or die "Impossible de créer '$path' : $!\n";
    return $fh;
}

# Valider que le chemin reste dans le répertoire autorisé
sub safe_path($base_dir, $user_path) {
    my $real = realpath(File::Spec->catfile($base_dir, $user_path))
        // die "Le chemin n’existe pas\n";
    my $base_real = realpath($base_dir)
        // die "Le répertoire de base n’existe pas\n";
    die "Parcours de chemin bloqué\n" unless $real =~ /^\Q$base_real\E(?:\/|\z)/;
    return $real;
}

Utilisez File::Temp pour les fichiers temporaires (tempfile(UNLINK => 1)) et flock(LOCK_EX) pour éviter les conditions de concurrence.

Exécution Sécurisée de Processus

Forme Liste de system et exec

use v5.36;

# Bon : Forme liste — pas d’interpolation shell
sub run_command(@cmd) {
    system(@cmd) == 0
        or die "Échec de la commande : @cmd\n";
}

run_command('grep', '-r', $user_pattern, '/var/log/app/');

# Bon : Capturer la sortie de manière sûre avec IPC::Run3
use IPC::Run3;
sub capture_output(@cmd) {
    my ($stdout, $stderr);
    run3(\@cmd, \undef, \$stdout, \$stderr);
    if ($?) {
        die "Échec de la commande (code $?) : $stderr\n";
    }
    return $stdout;
}

# Mauvais : Forme chaîne — injection shell !
sub bad_search($pattern) {
    system("grep -r '$pattern' /var/log/app/");  # Si $pattern = "'; rm -rf / #"
}

# Mauvais : Backticks avec interpolation
my $output = `ls $user_dir`;   # Risque d’injection shell

Utilisez aussi Capture::Tiny pour capturer stdout/stderr de manière sûre depuis des commandes externes.

Prévention d’Injection SQL

Placeholders DBI

use v5.36;
use DBI;

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

# Bon : Requêtes paramétrées — toujours utiliser des placeholders
sub find_user($dbh, $email) {
    my $sth = $dbh->prepare('SELECT * FROM users WHERE email = ?');
    $sth->execute($email);
    return $sth->fetchrow_hashref;
}

sub search_users($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({});
}

# Mauvais : Interpolation de chaîne dans SQL (vulnérabilité SQLi !)
sub bad_find($dbh, $email) {
    my $sth = $dbh->prepare("SELECT * FROM users WHERE email = '$email'");
    # Si $email = "' OR 1=1 --", retourne tous les utilisateurs
    $sth->execute;
    return $sth->fetchrow_hashref;
}

Listes Blanches pour Colonnes Dynamiques

use v5.36;

# Bon : Valider les noms de colonnes contre une liste blanche
sub order_by($dbh, $column, $direction) {
    my %allowed_cols = map { $_ => 1 } qw(name email created_at);
    my %allowed_dirs = map { $_ => 1 } qw(ASC DESC);

    die "Colonne invalide : $column\n"    unless $allowed_cols{$column};
    die "Direction invalide : $direction\n" unless $allowed_dirs{uc $direction};

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

# Mauvais : Interpolation directe d’une colonne choisie par l’utilisateur
sub bad_order($dbh, $column) {
    $dbh->prepare("SELECT * FROM users ORDER BY $column");  # SQLi !
}

DBIx::Class (Sécurité ORM)

use v5.36;

# DBIx::Class génère des requêtes paramétrées sûres
my @users = $schema->resultset('User')->search({
    status => 'active',
    email  => { -like => '%@example.com' },
}, {
    order_by => { -asc => 'name' },
    rows     => 50,
});

Sécurité Web

Prévention XSS

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

# Bon : Encoder la sortie pour le contexte HTML
sub safe_html($user_input) {
    return encode_entities($user_input);
}

# Bon : Encoder pour le contexte URL
sub safe_url_param($value) {
    return uri_escape_utf8($value);
}

# Bon : Encoder pour le contexte JSON
use JSON::MaybeXS qw(encode_json);
sub safe_json($data) {
    return encode_json($data);  # Gère l’échappement
}

# Échappement automatique des templates (Mojolicious)
# <%= $user_input %>   — échappé automatiquement (sûr)
# <%== $raw_html %>    — sortie brute (dangereux, utiliser uniquement pour du contenu de confiance)

# Échappement automatique des templates (Template Toolkit)
# [% user_input | html %]  — encodage HTML explicite

# Mauvais : Sortie brute dans du HTML
sub bad_html($input) {
    print "<div>$input</div>";  # XSS si $input contient <script>
}

Protection CSRF

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

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

Utilisez une comparaison en temps constant lors de la vérification des jetons. La plupart des frameworks web (Mojolicious, Dancer2, Catalyst) offrent une protection CSRF intégrée — préférez-les aux solutions maison.

Sécurité des Sessions et En-têtes

use v5.36;

# Session et en-têtes Mojolicious
$app->secrets(['secret-aléatoire-long-roté-régulièrement']);
$app->sessions->secure(1);          # HTTPS uniquement
$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');
});

Encodage de Sortie

Encodez toujours la sortie selon son contexte : HTML::Entities::encode_entities() pour le HTML, URI::Escape::uri_escape_utf8() pour les URLs, JSON::MaybeXS::encode_json() pour le JSON.

Sécurité des Modules CPAN

  • Épingler les versions dans cpanfile : requires 'DBI', '== 1.643';
  • Préférer les modules maintenus : Vérifier MetaCPAN pour les versions récentes
  • Minimiser les dépendances : Chaque dépendance est une surface d’attaque

Outillage de Sécurité

Politiques perlcritic

# .perlcriticrc — configuration orientée sécurité
severity = 3
theme = security + core

# Exiger l’ouverture à trois arguments
[InputOutput::RequireThreeArgOpen]
severity = 5

# Exiger les appels système vérifiés
[InputOutput::RequireCheckedSyscalls]
functions = :builtins
severity = 4

# Interdire l’évaluation de chaîne
[BuiltinFunctions::ProhibitStringyEval]
severity = 5

# Interdire les opérateurs backtick
[InputOutput::ProhibitBacktickOperators]
severity = 4

# Exiger la vérification de taint dans CGI
[Modules::RequireTaintChecking]
severity = 5

# Interdire l’ouverture à deux arguments
[InputOutput::ProhibitTwoArgOpen]
severity = 5

# Interdire les handles de fichier sous forme de mots nus
[InputOutput::ProhibitBarewordFileHandles]
severity = 5

Exécution de perlcritic

# Vérifier un fichier
perlcritic --severity 3 --theme security lib/MyApp/Handler.pm

# Vérifier tout le projet
perlcritic --severity 3 --theme security lib/

# Intégration CI
perlcritic --severity 4 --theme security --quiet lib/ || exit 1

Liste de Vérification Rapide

VérificationÀ valider
Mode taintDrapeau -T sur les scripts CGI/web
Validation d’entréeMotifs de liste blanche, limites de longueur
Opérations fichiersOuverture à trois arguments, vérification de parcours de chemin
Exécution de processusForme liste de system, pas d’interpolation shell
Requêtes SQLPlaceholders DBI, jamais d’interpolation
Sortie HTMLencode_entities(), échappement automatique des templates
Jetons CSRFGénérés et vérifiés sur les requêtes modifiant l’état
Configuration sessionCookies Secure, HttpOnly, SameSite
En-têtes HTTPCSP, X-Frame-Options, HSTS
DépendancesVersions épinglées, modules audités
Sécurité des regexPas de quantificateurs imbriqués, motifs ancrés
Messages d’erreurAucune trace de pile ou chemin divulgué aux utilisateurs

Anti-Patrons

# 1. Ouverture à deux arguments avec données utilisateur (injection de commande)
open my $fh, $user_input;               # Vulnérabilité CRITIQUE

# 2. system sous forme de chaîne (injection shell)
system("convert $user_file output.png"); # Vulnérabilité CRITIQUE

# 3. Interpolation de chaîne SQL
$dbh->do("DELETE FROM users WHERE id = $id");  # SQLi

# 4. eval avec entrée utilisateur (injection de code)
eval $user_code;                         # Exécution de code à distance

# 5. Faire confiance à $ENV sans le désinfecter
my $path = $ENV{UPLOAD_DIR};             # Peut être manipulé
system("ls $path");                      # Double vulnérabilité

# 6. Désactiver le taint sans validation
($input) = $input =~ /(.*)/s;           # Désinfection paresseuse — contre-productive

# 7. Données utilisateur brutes dans HTML
print "<div>Welcome, $username!</div>";  # XSS

# 8. Redirections non validées
print $cgi->redirect($user_url);         # Redirection ouverte

Souvenez-vous : La flexibilité de Perl est puissante mais exige de la discipline. Utilisez le mode taint pour le code web, validez toutes les entrées avec des listes blanches, utilisez les placeholders DBI pour chaque requête et encodez toute sortie selon son contexte. Défense en profondeur — ne reposez jamais sur une seule couche.

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 associés