Perl SecuritySAFE
The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.
Overview
The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.
649b2d7452ebOBSERVED · 2026-09-21What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
---
name: perl-security
description: テイントモード、入力バリデーション、安全なプロセス実行、DBIパラメータ化クエリ、Webセキュリティ(XSS/SQLi/CSRF)、perlcriticセキュリティポリシーを網羅する包括的なPerlセキュリティ。
origin: ECC
---
# Perlセキュリティパターン
入力バリデーション、インジェクション防止、セキュアコーディングプラクティスを網羅するPerlアプリケーションの包括的なセキュリティガイドライン。
## アクティベートするタイミング
- Perlアプリケーションでユーザー入力を処理するとき
- PerlのWebアプリケーション(CGI、Mojolicious、Dancer2、Catalyst)を構築するとき
- セキュリティ脆弱性についてPerlコードをレビューするとき
- ユーザー指定パスでファイル操作を実行するとき
- PerlからシステムコマンドをExecuteするとき
- DBIデータベースクエリを書くとき
## 仕組み
テイント対応の入力境界から始め、次に外側に移動する: 入力をバリデートしてアンテイントし、ファイルシステムとプロセス実行を制約内に保ち、どこでもパラメータ化されたDBIクエリを使用する。以下の例は、ユーザー入力、シェル、またはネットワークに触れるPerlコードをリリースする前に適用することが期待されるデフォルトを示す。
## テイントモード
Perlのテイントモード(`-T`)は外部ソースからのデータを追跡し、明示的なバリデーションなしに安全でない操作で使用されることを防ぐ。
### テイントモードの有効化
```perl
#!/usr/bin/perl -T
use v5.36;
# テイントされた: プログラム外からのもの
my $input = $ARGV[0]; # テイントされた
my $env_path = $ENV{PATH}; # テイントされた
my $form = <STDIN>; # テイントされた
my $query = $ENV{QUERY_STRING}; # テイントされた
# PATHを早期にサニタイズ(テイントモードで必要)
$ENV{PATH} = '/usr/local/bin:/usr/bin:/bin';
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
```
### アンテイントパターン
```perl
use v5.36;
# Good: 特定の正規表現でバリデートしてアンテイント
sub untaint_username($input) {
if ($input =~ /^([a-zA-Z0-9_]{3,30})$/) {
return $1; # $1はアンテイントされている
}
die "Invalid username: must be 3-30 alphanumeric characters\n";
}
# Good: ファイルパスをバリデートしてアンテイント
sub untaint_filename($input) {
if ($input =~ m{^([a-zA-Z0-9._-]+)$}) {
return $1;
}
die "Invalid filename: contains unsafe characters\n";
}
# Bad: 過度に許可的なアンテイント(目的を無効化する)
sub bad_untaint($input) {
$input =~ /^(.*)$/s;
return $1; # 何でも受け入れる — 無意味
}
```
## 入力バリデーション
### ブロックリストよりアローリスト
```perl
use v5.36;
# Good: アローリスト — 許可されるものを正確に定義
sub validate_sort_field($field) {
my %allowed = map { $_ => 1 } qw(name email created_at updated_at);
die "Invalid sort field: $field\n" unless $allowed{$field};
return $field;
}
# Good: 特定のパターンでバリデート
sub validate_email($email) {
if ($email =~ /^([a-zA-Z0-9._%+-]+\@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/) {
return $1;
}
die "Invalid email address\n";
}
sub validate_integer($input) {
if ($input =~ /^(-?\d{1,10})$/) {
return $1 + 0; # 数値に強制変換
}
die "Invalid integer\n";
}
# Bad: ブロックリスト — 常に不完全
sub bad_validate($input) {
die "Invalid" if $input =~ /[<>"';&|]/; # エンコードされた攻撃を見逃す
return $input;
}
```
### 長さ制約
```perl
use v5.36;
sub validate_comment($text) {
die "Comment is required\n" unless length($text) > 0;
die "Comment exceeds 10000 chars\n" if length($text) > 10_000;
return $text;
}
```
## 安全な正規表現
### ReDoS防止
壊滅的なバックトラッキングは重複するパターンにネストされた量詞が使用されるときに発生する。
```perl
use v5.36;
# Bad: ReDoSに脆弱(指数的バックトラッキング)
my $bad_re = qr/^(a+)+$/; # ネストされた量詞
my $bad_re2 = qr/^([a-zA-Z]+)*$/; # クラスにネストされた量詞
my $bad_re3 = qr/^(.*?,){10,}$/; # 繰り返される貪欲/怠惰な組み合わせ
# Good: ネストなしで書き直す
my $good_re = qr/^a+$/; # 単一の量詞
my $good_re2 = qr/^[a-zA-Z]+$/; # クラスに単一の量詞
# Good: バックトラッキングを防ぐためにpossessive量詞またはアトミックグループを使用
my $safe_re = qr/^[a-zA-Z]++$/; # Possessive (5.10+)
my $safe_re2 = qr/^(?>a+)$/; # アトミックグループ
# Good: 信頼されていないパターンにタイムアウトを適用
use POSIX qw(alarm);
sub safe_match($string, $pattern, $timeout = 2) {
my $matched;
eval {
local $SIG{ALRM} = sub { die "Regex timeout\n" };
alarm($timeout);
$matched = $string =~ $pattern;
alarm(0);
};
alarm(0);
die $@ if $@;
return $matched;
}
```
## 安全なファイル操作
### 3引数open
```perl
use v5.36;
# Good: 3引数open、レキシカルファイルハンドル、戻り値チェック
sub read_file($path) {
open my $fh, '<:encoding(UTF-8)', $path
or die "Cannot open '$path': $!\n";
local $/;
my $content = <$fh>;
close $fh;
return $content;
}
# Bad: ユーザーデータを使った2引数open(コマンドインジェクション)
sub bad_read($path) {
open my $fh, $path; # $pathが"|rm -rf /"なら、コマンドを実行!
open my $fh, "< $path"; # シェルメタキャラクターインジェクション
}
```
### TOCTOU防止とパストラバーサル
```perl
use v5.36;
use Fcntl qw(:DEFAULT :flock);
use File::Spec;
use Cwd qw(realpath);
# アトミックファイル作成
sub create_file_safe($path) {
sysopen(my $fh, $path, O_WRONLY | O_CREAT | O_EXCL, 0600)
or die "Cannot create '$path': $!\n";
return $fh;
}
# パスが許可されたディレクトリ内に留まることをバリデート
sub safe_path($base_dir, $user_path) {
my $real = realpath(File::Spec->catfile($base_dir, $user_path))
// die "Path does not exist\n";
my $base_real = realpath($base_dir)
// die "Base dir does not exist\n";
die "Path traversal blocked\n" unless $real =~ /^\Q$base_real\E(?:\/|\z)/;
return $real;
}
```
一時ファイルには`File::Temp`(`tempfile(UNLINK => 1)`)を使用し、レースコンディションを防ぐために`flock(LOCK_EX)`を使用する。
## 安全なプロセス実行
### リスト形式のsystemとexec
```perl
use v5.36;
# Good: リスト形式 — シェル補間なし
sub run_command(@cmd) {
system(@cmd) == 0
or die "Command failed: @cmd\n";
}
run_command('grep', '-r', $user_pattern, '/var/log/app/');
# Good: IPC::Run3で安全に出力をキャプチャ
use IPC::Run3;
sub capture_output(@cmd) {
my ($stdout, $stderr);
run3(\@cmd, \undef, \$stdout, \$stderr);
if ($?) {
die "Command failed (exit $?): $stderr\n";
}
return $stdout;
}
# Bad: 文字列形式 — シェルインジェクション!
sub bad_search($pattern) {
system("grep -r '$pattern' /var/log/app/"); # $patternが"'; rm -rf / #"なら
}
# Bad: 補間のあるバッククォート
my $output = `ls $user_dir`; # シェルインジェクションリスク
```
外部コマンドからstdout/stderrを安全にキャプチャするためには`Capture::Tiny`も使用する。
## SQLインジェクション防止
### DBIプレースホルダー
```perl
use v5.36;
use DBI;
my $dbh = DBI->connect($dsn, $user, $pass, {
RaiseError => 1,
PrintError => 0,
AutoCommit => 1,
});
# Good: パラメータ化クエリ — 常にプレースホルダーを使用
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->executeTrust audit
SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | NA |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (0)
No findings outside the package's declared scope.
Gates applied: no_behavioural_pass.
649b2d7452ebfull audit observations/trust-audit/skill/affaan-m__perl-security.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-09-21 | 649b2d7452eb | SAFE | B | 89 | first audit |
Questions
What does the Perl Security skill do?
The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.
Is Perl Security safe to install?
The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.
What can Perl Security access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
How current is this page?
The grade is for one exact copy of the source (649b2d7452eb), read on 2026-09-21. The repository is watched, and a new audit runs when it changes — this is the first audit.