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?

AIが書いたコードは「動く」のに半分は脆弱 — AI生成コードのセキュリティを「動くか」と「安全か」で分けて検証する実践ガイド

0
Posted at

はじめに:「動く」と「安全」は、実は別の話なんです

AIにコードを書かせると、ほんまに速い。

仕様をざっと伝えたら、数十秒で関数ができあがって、ローカルで動かしたらちゃんと動く。テストも通る。「もう完成やん」って気持ちになりますよね。僕もなります。

でも、ここでちょっと立ち止まって考えてみたいんです。

その「動いた」は、「安全だ」を意味してへんかもしれない。

車にたとえると分かりやすいかなと思います。エンジンがかかって前に進むことと、ブレーキがちゃんと効くことは、別の話ですよね。走ることだけ確認して「この車は安全だ」とは言わへんはずです。コードも同じで、「動く(機能する)」と「安全(攻撃に耐える)」は、別々に確かめるべき、別の検証軸なんです。

ここで、ちょっと背筋が伸びる数字を紹介します。

セキュリティ企業のVeracodeが2026年春に出した調査(GenAI Code Security Update、Spring 2026)で、150以上のLLMに対して、セキュリティの指示を一切与えずに80個のコーディング課題を解かせて、生成されたコードをSAST(静的解析)にかけました。結果はこうです。

  • コードが構文的に正しく「動く」率は、95%を超えている
  • でも、セキュリティ的に安全な率は、約55%でとどまっている(= 45%は既知の脆弱性を含んでいた
  • しかもこのセキュリティ合格率は、 2023年からほとんど横ばい 。モデルが賢くなっても改善していない

言語別だともっとはっきりします。Python 62%、C# 58%、JavaScript 57%、そして Java は29% 。Javaにいたっては、7割が何かしらの脆弱性を抱えていた計算になります。

「最新のすごいモデルを使えば安全になるんちゃうの?」と思いますよね。でもVeracodeいわく、モデルサイズの効果はごくわずかで、200億パラメータでも4000億パラメータでも、セキュリティの成績は同じ55%付近に集まったそうです。賢さと安全さは、別の能力なんです。

この記事は、「AI怖い、使うのやめよう」という話ではありません。むしろ逆です。AIで速く作れる時代だからこそ、 「動くか」と「安全か」を分けて検証する仕組み を一回作っておけば、明日の自分も、コードを使ってくれるユーザーも、ずっと助かる。そういう「攻め続けるための守り」を、無知の無知でも明日から手を動かせるところまで、具体的に書いていきます。

対象読者は、AIコーディングを日常的に使っていて、自分の書いた(書かせた)コードを本番に出す立場の人。セキュリティ専門じゃなくて大丈夫です。専門用語は出てくるたびに噛み砕きます。


なぜAIは"動くのに危ないコード"を書いてしまうのか

数字だけ見て「AIってダメやん」で終わったら、何も改善しません。大事なのは 「なぜそうなるのか」を構造で理解すること 。原因が分かれば、対策の置き場所も決まります。理由は大きく3つあると思っています。

理由1:AIは「平均的なコード」を学んでいる=平均的に危ないパターンも学んでいる

LLM(大規模言語モデル)は、世界中の膨大なコードを読んで「次に来そうなコード」を予測する仕組みです。つまり、 世の中に大量にあるコードの「平均」を再現しがち なんです。

ここで残酷な事実があって、世の中のコードには、安全でない書き方も大量に混ざっています。SQLを文字列連結で組み立てる古い書き方、APIキーをソースに直書きしたサンプル、パスワードをmd5で雑にハッシュ化したレガシー。こういう「動くけど危ない」パターンも、AIはしっかり学習してしまっている。だから、何も言わなければ、平均的に危ない書き方が混じってくる。これは精神論じゃなくて、学習の仕組みからくる構造的な話なんです。

理由2:AIは「動く」を最適化している。「安全」は、頼まないと出てこない

僕らがAIに渡す指示の多くは、「ユーザー一覧を取得する関数を書いて」みたいな 機能の要求 です。安全性については、たいてい何も言っていません。

AIは、与えられた要求を満たす最短ルートを探します。要求が「動くこと」なら、動くものを返す。「パラメータ化クエリを使え」「秘密は環境変数から読め」と明示しなければ、そこは最適化の対象になりません。Veracodeの調査が「セキュリティの指示なし」で測ったのは、まさに普段の僕らの使い方を再現したかったからなんですね。

理由3:いちばん怖いのは、人間側の「過信」

ここが本丸かもしれません。

スタンフォード大学の有名な研究(Perry, Srivastava, Kumar, Boneh「Do Users Write More Insecure Code with AI Assistants?」CCS 2023, arXiv:2211.03622)で、こんな結果が出ています。

  • AIアシスタントを使った参加者は、 使わなかった人より安全でないコードを書いた
  • それなのに、 「自分のコードは安全だ」と信じている度合いは高かった (過信)

つまり、AIがそばにいると、人は「できた感」が先に立って、検証の手をゆるめてしまう。「動いた、AIが書いたんやから大丈夫やろ」という安心が、いちばん危ない。 動く+自信は、安全の証明にはならへんのです。

この3つを並べると、対策の方向が見えてきます。AIの平均を上書きする指示(理由1・2への対策)と、人間の過信を埋める「機械的なチェック」(理由3への対策)。この両輪が要る、ということです。


AIがよく書いてしまう"危ないコード"カタログ(直し方つき)

抽象論だけだとピンとこないので、AIが量産しがちな脆弱性を、 before(危ない)→ after(安全) のコードで具体的に見ていきましょう。全部ダミーのサンプルです。ここを読むだけで「あ、これ自分のコードにもあるかも」が見つかるはずです。

(1) SQLインジェクション — ユーザーの入力が、命令文に化ける

SQLインジェクション とは、ユーザーが入力した文字列が、そのままデータベースへの命令文(SQL)の一部として実行されてしまう脆弱性です。攻撃者が入力欄に細工した文字列を入れると、本来見えないデータを抜かれたり、テーブルを消されたりします。

AIは、文字列を連結してSQLを組み立てる書き方を、けっこうやりがちです。

# before(危ない): 入力をそのまま連結している
def get_user(user_id):
    query = f"SELECT * FROM users WHERE id = '{user_id}'"
    return db.execute(query)
# user_id に  ' OR '1'='1  を入れられると、全件返ってしまう

直し方は パラメータ化クエリ(プレースホルダ) 。値を「文字列の一部」ではなく「あとから埋めるデータ」として渡すと、DBが値を命令として解釈しなくなります。

# after(安全): 値はプレースホルダで渡す
def get_user(user_id):
    query = "SELECT * FROM users WHERE id = %s"
    return db.execute(query, (user_id,))

ちなみにVeracodeの分類別では、SQLインジェクションはまだマシな方(モデルがパラメータ化を覚えてきている)なんですが、それでもゼロにはなっていません。「マシな方でこれ」と思っておくと、ちょうどいい緊張感かなと。

(2) クロスサイトスクリプティング(XSS) — 入力がそのまま画面で動いてしまう

XSS は、ユーザーの入力をそのままHTMLに埋め込んでしまい、入力の中に仕込まれたスクリプトがブラウザで実行されてしまう脆弱性です。他人のセッションを乗っ取られたりします。Veracodeの調査では、XSSのような「出力系」の脆弱性がとくに成績が悪く、AIがいちばん苦手にしている領域のひとつでした。

// before(危ない): ユーザー入力を生のままHTMLに差し込む
function renderComment(comment) {
  document.getElementById("box").innerHTML = "<p>" + comment + "</p>";
  // comment に <img src=x onerror=alert(1)> を入れられると実行される
}

直し方は 出力時のエスケープ(無害化) 。テキストとして扱う、もしくはフレームワークの自動エスケープに任せます。

// after(安全): テキストとして入れる(HTMLとして解釈させない)
function renderComment(comment) {
  const p = document.createElement("p");
  p.textContent = comment; // ここがポイント
  document.getElementById("box").replaceChildren(p);
}

ReactやVueなどのモダンフレームワークは、デフォルトで自動エスケープしてくれます。ただし dangerouslySetInnerHTMLv-html で自分から無効化すると、また穴が開く。AIがこの「危ない抜け道」を提案してくることがあるので要注意です。

(3) ハードコードされた秘密 — 鍵を玄関マットの下に置く

これは実地の監査でほんまに多いやつです。APIキーやパスワードを、ソースコードに直接書いてしまう。Gitにコミットした瞬間、履歴に永遠に残って、公開リポジトリなら世界中から見えます。

# before(危ない): 秘密をソースに直書き
STRIPE_API_KEY = "sk_live_abc123_THIS_IS_A_SECRET"
client = StripeClient(STRIPE_API_KEY)

直し方は 環境変数や秘密管理(Secrets Manager)から読む こと。そして、見本ファイルだけをコミットします。

# after(安全): 環境変数から読む。値はリポジトリに入れない
import os
STRIPE_API_KEY = os.environ["STRIPE_API_KEY"]
client = StripeClient(STRIPE_API_KEY)
# .env.example(これだけコミット。実値は書かない)
STRIPE_API_KEY=

# .gitignore に必ず .env を追加
echo ".env" >> .gitignore

AIは「とりあえず動くサンプル」を作るとき、プレースホルダのつもりで秘密っぽい文字列を埋めてくることがあります。それをそのままコミットしてしまう事故が、本当に多い。あとで詳しく書きますが、 秘密はAIに渡すプロンプトにも貼らない のが鉄則です。

(4) 弱いハッシュでパスワードを保存 — 金庫に紙の鍵

パスワードを保存するとき、md5やsha1みたいな高速なハッシュを使うのは危険です。これらは「速い」のが売りで、つまり攻撃者が総当たりするのも速い。AIは古いコードを学んでいるので、md5を平気で提案してきます。

# before(危ない): 速いハッシュ=総当たりしやすい
import hashlib
def hash_password(pw):
    return hashlib.md5(pw.encode()).hexdigest()

直し方は、 パスワード保存専用の、わざと遅いアルゴリズム (argon2id、bcrypt、scryptなど)を、ソルト付きで使うこと。

# after(安全): パスワード用のKDFを使う(ソルトは内部で自動付与)
from argon2 import PasswordHasher
ph = PasswordHasher()

def hash_password(pw: str) -> str:
    return ph.hash(pw)

def verify_password(stored: str, pw: str) -> bool:
    try:
        return ph.verify(stored, pw)
    except Exception:
        return False

「速いほうがええやん」という直感が、ここでは逆になる。これ、知らないと一生気づけないポイントなんですよね。

(5) 入力検証の欠如 — 「来たものは正しい」という前提が崩れる

最後は地味だけど効くやつ。APIが受け取ったデータを、検証せずにそのまま使ってしまうパターンです。型が違う、必須項目がない、想定外に長い、といった入力で、後ろの処理が壊れます。

// before(危ない): body をそのまま信じて使う
app.post("/orders", (req, res) => {
  const { quantity, productId } = req.body;
  createOrder(productId, quantity); // quantity が "-5" や "abc" でも通る
});

直し方は、 入り口でスキーマ検証 。zod(TS)やpydantic(Python)で、形・型・範囲を最初に固めます。

// after(安全): 入り口で形を保証する
import { z } from "zod";

const OrderSchema = z.object({
  productId: z.string().uuid(),
  quantity: z.number().int().min(1).max(100),
});

app.post("/orders", (req, res) => {
  const parsed = OrderSchema.safeParse(req.body);
  if (!parsed.success) return res.status(400).json({ error: "invalid input" });
  const { productId, quantity } = parsed.data;
  createOrder(productId, quantity);
});

「外から来るものは、ぜんぶ疑う」。これはセキュリティの基本姿勢で、AIに任せた部分こそ、この入り口の検証が抜けがちです。


発想の転換:「動くか」と「安全か」を、分けて確かめる

ここまでで「AIは何も言わないと危ない」「人間は過信しがち」という2つが見えました。じゃあどうするか。

ここで提案したい発想の転換は、 「AIにできるか」で考えるのをやめて、「どの検証を、誰(何)に任せるか」で考える ことです。これは僕が前に書いたコードマイグレーションの記事と同じ思想で、セキュリティにもそのまま効きます。検証の仕事を、3つのレイヤーに仕分けるんです。

レイヤー 担当 内容
① 決定的に検出できる 決定的ツール ルールで機械的に判定できるもの 秘密の直書き、既知の危険パターン、脆弱な依存
② 文脈に依存する AI(補助) コードの意図を踏まえた指摘 この認可チェックは要件を満たすか、設計上の穴
③ 受容するか判断する 人間 リスクを受け入れるか、止めるか 高深刻度の指摘の最終判断、不可逆操作の承認

ポイントは順番です。 ①で機械的に潰せるものを先に潰して、AI(②)に頼む範囲を「文脈判断が要るところ」だけに絞る 。そして最後の「これを本番に出していいか」という受容判断は、必ず人間(③)が握る。

なんでこの仕分けが大事かというと、 AIに「セキュリティチェックも全部やって」と丸投げするのは、過信の再生産だから です。AIはコードを書くときに危ないパターンを混ぜるのと同じ理由で、レビューするときも危ないパターンを見逃します。自分の盲点は、自分では見えにくい。だから、機械的に判定できるところは、ブレない決定的ツールに任せる。これが効くんです。

次の章で、この仕分けを「作る前から守る」開発フローに落とし込みます。


作る前から守る:シフトレフトの4ステップ

セキュリティの世界に シフトレフト という言葉があります。開発の流れを左から右(設計→実装→テスト→リリース)に並べたとき、問題の発見をできるだけ「左(早い段階)」に寄せる、という考え方です。バグも脆弱性も、後で見つけるほど直すコストが跳ね上がる。だから早く気づこう、と。

AI生成コードに対して、このシフトレフトを4ステップで組みます。

ステップ1:生成「前」に、制約を先に渡す(secure-by-prompt)

理由2で見たとおり、AIは頼まれたことしか最適化しません。なら、 最初から安全の制約を渡しておけばいい 。これだけで危ない初期出力はかなり減ります。

【セキュアコード生成プロンプト(システムプロンプト/前置きに入れる)】
あなたは安全なコードを書くシニアエンジニアです。以下を常に守ってコードを書いてください。

- 秘密(APIキー/パスワード/トークン/接続文字列)は絶対にハードコードしない。
  環境変数か秘密管理から読む。サンプルでもダミーのプレースホルダのみ。
- DBアクセスは必ずパラメータ化クエリ(プレースホルダ)を使う。文字列連結でSQLを組まない。
- 外部からの入力は信用しない。入り口でスキーマ検証(型・必須・範囲)を行う。
- 出力時はエスケープし、XSSを避ける。自動エスケープを自分から無効化しない。
- パスワードは argon2id / bcrypt / scrypt 等の専用KDFで保存する。md5/sha1は使わない。
- セキュリティ上の判断をしたら、コードのコメントで理由を一言添える。
- 上記に反する実装しか思いつかない場合は、コードを書かずに理由と代替案を述べる。

ただし、ここで釘を刺しておきたいんです。 secure-by-promptは「入口」であって「ゴール」じゃない 。Veracodeの調査は「指示なし」で測ったものですが、指示を足してもセキュリティが完璧になるわけではありません。プロンプトはAIの平均を少し押し上げるだけ。だから次のステップが本命です。

ステップ2:生成「直後」に、決定的ツールでスキャンする

AIが書いたコードは、コミットする前に 機械的にスキャン します。人間のレビューに回す前に、機械で潰せるものは潰す。ここが3レイヤーの①です。

主役は2つ。 Gitleaks (秘密の検出に特化した軽量スキャナ)と、 Semgrep (SAST=コードの危険パターンを意味的に検出する静的解析ツール)。これを pre-commitフック に仕込むと、「コミットしようとした瞬間に、危ないものをブロックしてくれる」ようになります。家を出る前の戸締まり確認を、自動でやってくれるイメージです。

# .pre-commit-config.yaml
repos:
  # Gitleaks: 秘密(APIキー・トークン等)の直書きをブロック
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.24.2
    hooks:
      - id: gitleaks

  # Semgrep: SAST(OWASP Top 10 + 秘密検出のルールセット)
  - repo: https://github.com/semgrep/pre-commit
    rev: v1.166.0
    hooks:
      - id: semgrep
        args: ["--config=p/owasp-top-ten", "--config=p/secrets", "--error"]

導入は一度だけ。

pip install pre-commit
pre-commit install
# 以降、コミットのたびに自動でスキャンが走り、ヒットしたらコミットが止まる
pre-commit run --all-files   # 既存コードを今すぐ全部スキャンしたいとき

ここで効くのが「ブレないこと」です。AIは同じコードを2回レビューさせると違うことを言うこともありますが、SemgrepやGitleaksは同じ入力に同じ判定を返す。 決定的だから、ゲート(門番)にできる んです。

ステップ3:AIに、文脈依存のセキュリティレビューをさせる

機械で潰せないのが、 文脈に依存する穴 です。「このエンドポイント、認可チェックが要件を満たしてる?」「この権限設計、抜け道ない?」みたいなやつ。ここは3レイヤーの②、AIの出番です。

ただし、 AIのレビューは「権威」ではなく「もう一つの目」 として扱います。指摘には必ず根拠(ファイルと行)を出させて、不明なら無理に断定させず「分からない」と言わせる。これがハルシネーション(それっぽい嘘)対策になります。

【セキュリティレビュープロンプト】
あなたはセキュリティレビュアーです。以下のコードを OWASP Top 10 の観点でレビューしてください。

出力ルール:
- 指摘ごとに「該当ファイル:行番号」「脆弱性の種類(CWE名)」「深刻度(critical/high/medium/low)」
  「なぜ危険か」「修正案」を表で示す。
- 確証が持てないものは断定せず「要確認」とラベルし、確認方法を書く。
- 問題が見つからない箇所を「安全」と断言しない。「この観点では問題を検出できなかった」と書く。
- 最終的な受容判断(本番に出すか)は人間が行う前提で、判断材料だけを提示する。

レビュー対象:
(ここにコードを貼る。※秘密情報・本番データは絶対に貼らない)

最後の一文が大事です。 受容判断(出すか止めるか)は人間が握る 。AIは材料を出す係であって、決裁者ではありません。

ステップ4:CIで「門」を立てる(高深刻度はブロック)

最後に、pre-commitをすり抜けたり、入れ忘れた人がいても大丈夫なように、 CI(GitHub Actionsなど)で同じスキャンをもう一度 走らせます。pre-commitは「各自の善意」に頼る部分があるので、リポジトリ側の門も立てておく。ベルトとサスペンダー、両方つけるイメージです。

# .github/workflows/security-gate.yml
name: security-gate
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # Gitleaks が履歴も見られるように

      - name: Secret scan (Gitleaks)
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: SAST (Semgrep)
        uses: semgrep/semgrep-action@v1
        with:
          config: >-
            p/owasp-top-ten
            p/secrets
            .semgrep/   # 自社の禁止パターン用カスタムルール

組織独自の「これは絶対ダメ」を、カスタムSemgrepルールで足すこともできます。たとえば、危険な eval の使用を禁止するならこう書けます。

# .semgrep/no-eval.yml
rules:
  - id: no-eval-on-user-input
    languages: [python]
    severity: ERROR
    message: "ユーザー入力を eval に渡してはいけません(任意コード実行の危険)"
    pattern: eval(...)

そして、高深刻度(critical/high)の指摘が残っているうちは、マージできないようにする。 「人間が見て、受け入れると決めるまで、止まる門」 を作っておくわけです。

この4ステップを並べると、3レイヤーの仕分けがそのまま開発フローになっているのが分かると思います。①機械(ステップ2・4)→②AI(ステップ3)→③人間(最終承認)。AIの過信を、機械のブレなさと人間の判断で挟み込む構造です。


ここだけは外せない、安全の鉄則

便利な仕組みも、土台を踏み外すと逆に事故ります。最後に「これだけは」という鉄則を。

鉄則1:秘密は、AIへのプロンプトにもログにも貼らない(最重要)

これがいちばん見落とされます。コードの中の秘密は気をつけても、 「このエラー直して」とAIに本物のAPIキー入りのコードや、本番のログを貼ってしまう 事故が起きます。

AIに渡したテキストは、どこかに保存されたり、学習に使われたり、外部に送られる可能性がある経路に乗ります。秘密や個人情報、本番データは、AIに渡す前に必ずダミーに置き換える。スキャナのログやエラー出力にも、秘密が混ざらないようにする。 「AIに渡す=外に出す」と思っておくくらいでちょうどいい と思います。

鉄則2:AIのセキュリティレビューを、最終判定にしない

繰り返しになりますが、AIは自分が書くときに見逃すパターンを、レビューでも見逃します。AIのOKは「一つの参考意見」。決定的ツールでの裏取りと、人間の目を必ず重ねる。 「AIが大丈夫って言ったから」は、Stanfordの研究が示した"過信"そのもの です。

鉄則3:高深刻度と不可逆操作は、人間が承認する

本番DBへの破壊的な変更、課金、公開、削除、デプロイ。こういう「やり直しがきかない操作」と、critical/highの脆弱性指摘は、AIや自動化に勝手に通させない。必ず人間が「これは受け入れる/これは止める」と判断する門を、構造として置いておく。

鉄則4:AIが提案した「依存」も、untrustedとして扱う

AIは、 実際には存在しないパッケージ名 を、もっともらしく提案してくることがあります(slopsquattingと呼ばれる現象)。攻撃者がその「ありそうな名前」を先回りして悪意あるパッケージとして登録していたら、入れた瞬間にアウトです。AIが npm installpip install を勧めてきたら、名前を一度公式レジストリで確かめる。依存もまた、外から来るものとして疑うわけです。


人間が握るもの、AIに任せるもの

ここまでを、役割分担の表にまとめます。AIに任せて速くするところと、人間が握って外さないところを、はっきり分けるのがコツです。

工程 人間(What/Why=何を・なぜ) AI(How=どう実装するか)
制約設計 どの脅威を防ぐか、何を許容するか secure-by-promptの文面の下書き
実装 設計判断、認可・権限の境界 制約に沿ったコードの生成
機械チェック ルール(何をブロックするか)の決定 (担当外。決定的ツールが実施)
文脈レビュー 指摘の妥当性の最終判断 根拠つきの指摘の洗い出し
受容判断 本番に出すか止めるか 判断材料の提示のみ
不可逆操作 承認(人間ゲート) 実行しない

合言葉は、 「何を・なぜ」は人間、「どう」はAI 。これはセキュリティに限らず、AI時代の開発全体に効く分け方だと思っています。

よくある落とし穴6つ

  1. AIに「セキュアに書いて」と頼んで満足する … 入口に過ぎない。決定的スキャンで裏取りする。
  2. 動作テストが通ったから安全だと思う … 動くと安全は別軸。SASTと秘密スキャンは別物。
  3. 秘密をAIへのプロンプトに貼る … ダミーに置き換える。ログにも出さない。
  4. AIのレビューを最終判定にする … 自分の盲点は自分で見えない。機械+人間で挟む。
  5. CIゲートを警告どまりにする … 高深刻度はブロックしないと、結局スルーされる。
  6. AIが勧めた依存をそのまま入れる … 存在確認と最小限の権限で。

撤退ライン(無理しないための線)

  • スキャンの指摘が多すぎて回らないときは、まず critical/highだけ に絞って、源流(新規コミット)からブロックする。過去分は責めずに、徐々に。
  • 自動修正をAIに任せて、挙動が変わってしまうなら止める。 挙動を変えずに直す には、先に振る舞いを固定するテスト(仕様化テスト)を置く。
  • 不可逆操作にぶつかったら、自動を止めて人間に戻す。これは速度より優先。

おわりに:今日の戸締まりは、明日の自分への「あざっす」

長くなったので、最後に大事なところだけ。

AIで「動くもの」を作るのは、もう一瞬です。でも、 「動く」と「安全」は別の検証軸 で、AIは何も言わなければ平均的に危ない書き方を混ぜてくるし、人間はAIがそばにいると過信して手をゆるめてしまう。Veracodeの「構文95%・セキュリティ55%で2年横ばい」と、Stanfordの「使うと安全でないのに、安全だと信じる」は、その2つを冷たく裏づけています。

だからこそ、対策はシンプルです。 「動くか」と「安全か」を、分けて確かめる仕組みを一回作る。 生成前に制約を渡し、生成直後に機械でスキャンし、文脈はAIに洗い出させ、最後は人間が受容を判断する。決定的に潰せるものは決定的ツールに、文脈はAIに、受容判断は人間に。この3レイヤーの仕分けが、過信を構造で埋めてくれます。

僕がこういう「守り」を、責める軸じゃなくて思いやりの軸で捉えたいのには理由があります。脆弱性って、攻撃されてから「なんで気づかんかったんや」と過去の自分を責めても、もう遅いんですよね。それより、今日コミット前のスキャンを一個仕込んでおく。pre-commitを一回入れておく。それが、半年後の自分や、コードを使ってくれるユーザーへの 「先に守っといてくれて、あざっす」 になる。今日の戸締まりは、明日の自分への小さなプレゼントなんです。

そして、 安全に書ける力・検証する仕組みは、AIに奪われへん資産 だと思います。コードを書く速さはコモディティになっていくけど、「動くものを、安全に出せる」という判断と仕組みは、積み上がっていく。これはまさに、コードを資産(Capital)として育てるという話そのものです。

明日からの最初の4ステップ

  1. 今のプロジェクトで pre-commit install して、 Gitleaks+Semgrep を入れる(戸締まりの自動化)。
  2. pre-commit run --all-files で、 既存コードを一回スキャン してみる(まず現状を知る)。
  3. AIに渡すプロンプトの前に、 secure-by-promptの制約文 を一枚貼る(入口を底上げ)。
  4. CIに security-gate.yml を足して、 高深刻度はマージをブロック する門を立てる。

全部やらなくていいんです。今日は1番だけでも。その一個の戸締まりが、明日のあなたを助けてくれるはずやから。


参考にした主な一次情報:

  • Veracode「Spring 2026 GenAI Code Security Update」(セキュリティ合格率55%/構文95%/言語別の成績)
  • Neil Perry, Megha Srivastava, Deepak Kumar, Dan Boneh「Do Users Write More Insecure Code with AI Assistants?」CCS 2023(arXiv:2211.03622)
  • OWASP Top 10、Semgrep(p/owasp-top-ten・p/secrets)、Gitleaks 公式ドキュメント
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?