0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Repomixのセキュリティチェック、AWSキーIDだけ検出漏れした理由を実測

0
Posted at

はじめに

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の内蔵チェックには反映されない(単体の secretlint CLIでは反映される)
  • 「セキュリティチェックを通過した = 機密情報ゼロ」と鵜呑みにするのは危険、というのが実測から得た結論

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つです。

  1. enableIDScanRule は options.enableIDScanRule ?? false — デフォルトは false
  2. 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 で除外するのが安全

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?