はじめに
Repomix はリポジトリ全体を1つのファイルにパックし、LLMに読み込ませやすい形式に変換するCLIツールです。GitHub上で27.2k Star(2026-07-16時点)を集めており、パック時に自動でシークレットスキャンを行う「Security Check」機能を内蔵しています。
このセキュリティチェックを実際に動かしてみたところ、AWSのSecret Access Key(40文字の秘密鍵)は検出されるのに、AWS Access Key ID(AKIAから始まる20文字の識別子)は検出されない という非対称な挙動に遭遇しました。
この記事では、その挙動を実際に再現し、Repomixが内部で使っているSecretlintのソースコードを読んで根本原因を特定し、さらに「設定ファイルで解決できるか」まで実機で検証した記録をまとめます。
この記事で分かること
- Repomixの
--compressオプションによるトークン削減効果の実測値 - AWS Access Key IDが検出されずAWS Secret Access Keyだけが検出される、という非対称な挙動の再現手順
- その根本原因(Secretlintの
enableIDScanRuleオプションのデフォルト値と、Repomixが設定を渡していない実装) -
.secretlintrc.jsonを書いてもRepomixの内蔵チェックには反映されない、という実証結果 - 実務での回避策
前提環境
- OS: Linux 6.18.5(x86_64)
- Node.js: v22.22.2
- npm: 10.9.7
- repomix: 1.16.1(
npx --yes repomix --versionで確認) - @secretlint/core / @secretlint/secretlint-rule-preset-recommend: 13.0.2
TL;DR
- Repomixの
--compressはコメント・空白等を削る簡易圧縮で、手元の検証(25ファイル・68,097トークン)では約65%のトークン削減が確認できた - Repomixのデフォルトのセキュリティチェックは、AWS Secret Access Key(40文字)は検出するが、AWS Access Key ID単体は検出しない
- 原因はSecretlintの
@secretlint/secretlint-rule-awsルールにあるenableIDScanRuleオプションがデフォルトfalseであること -
さらに重要なのは、Repomixがユーザーの
.secretlintrc.jsonを一切読み込まない実装になっている点。設定ファイルでオプションを変えても、Repomixの内蔵チェックには反映されない(単体のsecretlintCLIでは反映される) - 「セキュリティチェックを通過した = 機密情報ゼロ」と鵜呑みにするのは危険、というのが実測から得た結論
Repomixを実際に動かす
まずは素の動作確認です。手元のリポジトリの scripts/ ディレクトリ(Node.jsスクリプト25ファイル)を対象に、圧縮なし・圧縮ありの両方でパックしてトークン数を比較しました。
$ npx --yes repomix .
📈 Top 5 Files by Token Count:
──────────────────────────────
1. publish-qiita.js (8,142 tokens, 22,814 chars, 12%)
2. check-qiita-comments.js (6,268 tokens, 18,573 chars, 9.2%)
3. analyze-qiita-performance.js (5,763 tokens, 15,658 chars, 8.5%)
4. post-x-speed.js (5,057 tokens, 15,499 chars, 7.4%)
5. watch-kinako-x.js (4,406 tokens, 12,980 chars, 6.5%)
🔎 Security Check:
──────────────────
✔ No suspicious files detected.
📊 Pack Summary:
────────────────
Total Files: 25 files
Total Tokens: 68,097 tokens
Total Chars: 203,694 chars
--compress によるトークン削減実測
同じディレクトリに --compress を付けて再実行します。
$ npx --yes repomix --compress .
📈 Top 5 Files by Token Count:
──────────────────────────────
1. publish-qiita.js (3,969 tokens, 7,309 chars, 16.9%)
2. check-qiita-comments.js (2,848 tokens, 6,195 chars, 12.1%)
3. watch-kinako-x.js (2,167 tokens, 4,575 chars, 9.2%)
4. x-engagement-auto-follow.js (2,045 tokens, 4,646 chars, 8.7%)
5. post-x-speed.js (1,487 tokens, 3,144 chars, 6.3%)
📊 Pack Summary:
────────────────
Total Files: 25 files
Total Tokens: 23,548 tokens
Total Chars: 52,530 chars
68,097トークン → 23,548トークンで約65.4%の削減 でした。--compress はTree-sitterでASTを解析し、コメント・空行・関数の中身などを間引く仕組みで、コードの「シグネチャ」を優先的に残す設計です(大枠の構造をLLMに読ませたいだけなら十分実用的な削減率でした)。
セキュリティチェックの非対称性を実測する
ここからが本題です。Repomixは「1つのファイルに機密情報とみなせる文字列があれば、そのファイルごと出力から除外する」というSecurity Checkを内蔵しています。これをAWSの認証情報2種類(Access Key ID / Secret Access Key)で個別に検証しました。
検証用に、それぞれ1種類の認証情報だけを含むダミーファイルを2つ用意します(実在しないダミー値です)。
ケース1: AWS Access Key IDのみ
// case1-test/aws-id-only.js
const accessKeyId = "AKIA3XJ9QM7VZ2K8YHNP";
module.exports = { accessKeyId };
$ npx --yes repomix .
🔎 Security Check:
──────────────────
✔ No suspicious files detected.
📊 Pack Summary:
────────────────
Total Files: 1 files
Total Tokens: 415 tokens
検出されませんでした。 ファイルはそのまま出力に含まれます。
ケース2: AWS Secret Access Keyのみ
// case2-test/aws-secret-only.js
const secretAccessKey = "TuXNbXsK8nhThCzS89zF5Pf/JSa8iVg90nuXZMLG";
module.exports = { secretAccessKey };
$ npx --yes repomix .
🔎 Security Check:
──────────────────
1 suspicious file(s) detected and excluded from the output:
1. aws-secret-only.js
- 1 security issue detected
These files have been excluded from the output for security reasons.
📊 Pack Summary:
────────────────
Total Files: 0 files
こちらは検出され、ファイルごと出力から除外されました。
同じ「AWSの認証情報」でも、Access Key IDとSecret Access Keyで挙動が完全に非対称であることが確認できました。
なぜAccess Key IDだけ検出されないのか
RepomixのSecurity CheckはSecretlint(@secretlint/core + @secretlint/secretlint-rule-preset-recommend)をライブラリとして呼び出しています。実行に使われたnpxキャッシュから該当コードを読みました。
まず、Repomix側のワーカー実装です(repomix/lib/core/security/workers/securityCheckWorker.js)。
export const createSecretLintConfig = () => ({
rules: [
{
id: '@secretlint/secretlint-rule-preset-recommend',
rule: creator,
},
],
});
const cachedConfig = createSecretLintConfig();
見ての通り、@secretlint/secretlint-rule-preset-recommend を オプションなし で登録しているだけです。ユーザー側の設定ファイルを読み込む処理はどこにもありません。
次に、preset-recommend内にバンドルされているAWSルールの実装(@secretlint/secretlint-rule-preset-recommend/module/index.js)を見ると、この非対称性の根拠が出てきます。
const creator$s = {
// ...
create(context, options) {
const normalizedOptions = {
allows: options.allows || [],
enableIDScanRule: options.enableIDScanRule ?? false,
};
return {
file(source) {
if (normalizedOptions.enableIDScanRule) {
reportAWSAccessKey({ t, source, context, options: normalizedOptions });
reportAWSAccountID({ t, source, context, options: normalizedOptions });
}
reportAWSSecretAccessKey({ t, source, context, options: normalizedOptions });
},
};
},
};
ポイントは2つです。
-
enableIDScanRuleはoptions.enableIDScanRule ?? false— デフォルトはfalse -
reportAWSAccessKey(Access Key ID検出)とreportAWSAccountID(アカウントID検出)はenableIDScanRuleがtrueのときしか呼ばれない。一方reportAWSSecretAccessKey(Secret Access Key検出)は 常に無条件で呼ばれる
つまりSecretlint自体の設計として、Access Key ID単体の検出はオプトイン(既定オフ)、Secret Access Key検出は既定オンという非対称な仕様になっており、Repomixは enableIDScanRule を明示的に有効化していないため、Access Key IDが常にすり抜ける、というのが直接の原因でした。
なぜAccess Key IDの検出が既定オフなのか:
@secretlint/secretlint-rule-awsの公式READMEには「これらのルールはfalse-positiveになりうるため、有効にする場合はtrueを設定してください」という趣旨の説明があり、偶発的な一致(false positive)の多さが既定オフの理由として明記されています。
Repomix側で設定変更できるか
「.secretlintrc.json で enableIDScanRule: true を指定すれば直るのでは」と考え、実際にRepomixの実行ディレクトリに設定ファイルを置いて試しました。
{
"rules": [
{
"id": "@secretlint/secretlint-rule-preset-recommend",
"rules": [
{ "id": "@secretlint/secretlint-rule-aws", "options": { "enableIDScanRule": true } }
]
}
]
}
このファイルを置いた状態で npx repomix . を再実行しましたが、結果は変わらず、Access Key IDのみのファイルは検出されませんでした。先ほど読んだ securityCheckWorker.js の通り、Repomixはユーザーの設定ファイルを一切参照せずハードコードされた createSecretLintConfig() だけを使っているため、これは実装上当然の結果です。
念のため、同じ .secretlintrc.json を単体の secretlint CLIに対して使うと有効になることも確認しました。
# デフォルト設定(enableIDScanRule 未指定)
$ npx --yes secretlint --secretlintrc .secretlintrc-default.json case1-test/aws-id-only.js
(何も出力されず、exit code 0)
# enableIDScanRule: true を指定
$ npx --yes secretlint --secretlintrc .secretlintrc-idscan.json case1-test/aws-id-only.js
/tmp/.../case1-test/aws-id-only.js
2:21 error [AWSAccessKeyID] found AWS Access Key ID: ********************
✖ 1 problem (1 error, 0 warnings, 0 infos)
secretlint 単体では enableIDScanRule: true で確かに検出されます(exit code 1)。つまり 設定ファイルそのものは正しく機能するが、Repomixがその設定ファイルを読む導線を持っていない というのが正確な結論です。「Repomixの実行ディレクトリに .secretlintrc.json を置けば挙動を変えられる」という思い込みは、今回の実測では成立しませんでした。
実務での回避策
Repomixでリポジトリをパックして生成AIに読ませる運用をしている場合、以下を意識すると安全側に倒せます。
- 「Security Check: No suspicious files detected」は「Secret Access Keyのような特定パターンが見つからなかった」ことの証明であって、「機密情報ゼロ」の証明ではないと理解しておく
- Access Key IDや各種APIキーのIDのように、それ単体では検出対象外のものが混入しうる設定ファイル・envサンプルは、
.repomixignoreで明示的にパック対象から除外する - CIパイプライン等で二重チェックしたい場合は、Repomixとは別に
secretlintを単体実行し、.secretlintrc.jsonでenableIDScanRule: trueを明示指定する(Repomix側の設定では効かない点に注意)
まとめ
-
--compressは手元の25ファイル・68,097トークンの検証で約65%のトークン削減が確認できた - Repomixのセキュリティチェックは、AWS Secret Access Keyは検出するがAWS Access Key ID単体は検出しないという非対称な挙動が実測で確認できた
- 原因はSecretlintの
enableIDScanRule(デフォルトfalse)にあり、Repomixはこのオプションを有効化せず、かつユーザーの.secretlintrc.jsonも読み込まない実装になっている - 「セキュリティチェック通過」を過信せず、機密情報を含みうるファイルは事前に
.repomixignoreで除外するのが安全
参考リンク
- Repomix (GitHub) — Star数・バージョン確認元
-
Secretlint (GitHub) —
@secretlint/secretlint-rule-awsの実装元 -
Repomix公式ドキュメント —
--compressオプションの説明