Media > AI活用ユースケース > 情報システム > 部署で作った Python・GAS の業務用スクリプトを毎月集めて読み、認証情報の直書き・全件削除・例外の握りつぶしなど危ない書き方を判定して持ち主に直し方を返す

部署で作った Python・GAS の業務用スクリプトを毎月集めて読み、認証情報の直書き・全件削除・例外の握りつぶしなど危ない書き方を判定して持ち主に直し方を返す

実装ステータス:構成例 技術的に実現可能な構成として設計したもの。自社未検証

各部署が作った Python と Google Apps Script のスクリプトを毎月集め、認証情報の直書きや確認なしの全件削除などの危ない書き方を判定します。該当する行と直し方を持ち主に返し、情報システムの担当は判定の確認と難しいものに絞って関わります。

サマリー
生成AI
ChatGPT/Claude/Gemini
対象業界
商社/物流/製造
対象部門
情報システム
対象業務
内容確認・チェック
主な課題
人手が足りない/属人化している/確認ミスが多い
AIで行う処理
判定
主な効果
品質標準化/属人化解消/工数削減
導入難易度
★★★☆☆
実装レベル
半自動化
費用感
API連携(中)
人間の確認
必須
現在工数
60h/月
AI導入後
12h/月
想定削減
80%
年間削減
576h
モデル条件による試算値です。実在企業の実績ではありません。

01導入前 / 導入後の業務フロー

導入前(Before)
  1. 台帳から、今月点検するスクリプトの一覧を作る
  2. リポジトリや Apps Script のエディタを開き、ソースを読む
  3. 危ない書き方があれば、行番号と内容をメモする
  4. 持ち主にメールで知らせ、直し方を説明する
  5. 直ったものを読み直し、台帳に点検の日付を付ける
導入後(After)
  1. 自動毎月1日に、台帳から今月点検するスクリプトの一覧を作る
  2. 自動Python はリポジトリから、Apps Script は Apps Script API でソースを取り出す
  3. 自動Python は Bandit で解析し、結果を JSON で受け取る。Apps Script はマニフェストの権限を取り出す
  4. 自動文字列の検索で、APIキーやトークンらしい文字列を探して印を付ける
  5. 自動Claude API に、ソース、解析の結果、台帳の目的を渡し、8つの観点で判定させる
  6. 自動判定の結果を、観点ごとの該当の有無・行・重さ・直し方の形で受け取り、点検の一覧に書く
  7. 人担当者が「重い」と出たものと、AIが判断できなかったものを開いて確かめる
  8. 人担当者が確かめた指摘を、持ち主に送る。直し方の文はAIの下書きを使う
  9. 人持ち主が直したものは、翌月の点検で同じ観点が消えたかを見る
各工程の詳しい説明を読む
  1. 台帳から、今月点検するスクリプトの一覧を作る
  2. リポジトリや Apps Script のエディタを開き、ソースを読む
  3. 危ない書き方があれば、行番号と内容をメモする
  4. 持ち主にメールで知らせ、直し方を説明する
  5. 直ったものを読み直し、台帳に点検の日付を付ける

(a)120本を読み切れない。 1本30分でも月60時間です。兼務の2名には無理な量で、定期の見直しの番が来たものは、ほとんど読まれないまま点検の日付だけが更新されています。

(b)見る観点が人によって違う。 1人はセキュリティの経験があり、直書きのキーと外部への送信をよく見ます。もう1人は業務システムの経験が長く、削除や上書きの条件をよく見ます。 どちらが読んだかで、見つかるものが違います。

(c)事故の後に見つかる。 昨年、営業所のスクリプトが表の「出荷済み」の行を消すはずが、条件の列を取り違えてその月の受注の表の全行を消しました。 版の履歴から戻せましたが、半日の作業が止まりました。そのスクリプトは登録時に点検済みでしたが、点検の後に変更されていました。

(d)直し方の説明に時間がかかる。 「パスワードを直書きしないでください」と書くだけでは、持ち主は何に置き換えればよいか分かりません。Apps Script ならスクリプトのプロパティ、Python なら環境変数や秘密情報の置き場所、と1件ずつ説明しています。

  1. 【自動】 毎月1日に、台帳から今月点検するスクリプトの一覧を作る
  2. 【自動】 Python はリポジトリから、Apps Script は Apps Script API でソースを取り出す
  3. 【自動】 Python は Bandit で解析し、結果を JSON で受け取る。Apps Script はマニフェストの権限を取り出す
  4. 【自動】 文字列の検索で、APIキーやトークンらしい文字列を探して印を付ける
  5. 【自動】 Claude API に、ソース、解析の結果、台帳の目的を渡し、8つの観点で判定させる
  6. 【自動】 判定の結果を、観点ごとの該当の有無・行・重さ・直し方の形で受け取り、点検の一覧に書く
  7. 【人】 担当者が「重い」と出たものと、AIが判断できなかったものを開いて確かめる
  8. 【人】 担当者が確かめた指摘を、持ち主に送る。直し方の文はAIの下書きを使う
  9. 【人】 持ち主が直したものは、翌月の点検で同じ観点が消えたかを見る

7番目が、この設計の分かれ目です。人が開くのは全件ではありません。 該当なしと出たスクリプトは一覧で流し見て、重いものと判断できなかったものだけを開きます。 全件を開く設計にすると、60.0時間はほとんど減りません。

8番目で指摘を送るのは、人です。 AIの指摘が誤っていることもあります。持ち主にとって、情報システム部からの指摘は「直さなければならないもの」です。 誤った指摘が届けば、動いているスクリプトを壊す直しにつながります。

02今回想定するシステム構成

構成図
スクリプトの登録の台帳(今月の点検の一覧)
   ▼【トリガー】毎月1日
収集のプログラム(情報システム部が用意)
   ├──▶ Python:社内のリポジトリから取り出す → Bandit で解析(JSON)
   ├──▶ Apps Script:Apps Script API(projects.getContent)で取り出す
   │      → マニフェストの権限を取り出す
   ├──▶ キー・トークンらしい文字列の検索
   ▼
Claude API ── 8つの観点で判定(構造化出力)
   │   ① 認証情報の直書き ② 全件の削除・上書き ③ 例外の握りつぶし
   │   ④ 外部への送信先 ⑤ 権限の広さ ⑥ 宛先の直書き
   │   ⑦ 通信の検証の無効化 ⑧ 終わらない繰り返し
   ▼
点検の一覧(重い/注意/該当なし/判断できない)
   ▼
【担当者が重いものと判断できないものを確かめる】→ 持ち主へ直し方を送る
役割想定する製品代替候補
処理Claude API(8つの観点の判定と直し方の下書き)OpenAI API、Gemini API
解析Bandit(Python のソースの静的解析)Semgrep
収集Apps Script API(Apps Script のソースの取り出し)clasp
台帳スクリプトの登録の台帳(いま使っているもの)-

新しく足すのは、収集のプログラムと、Claude API の利用だけです。 台帳とリポジトリは変えません。読んで探す部分を、解析とAIの判定に替えます。

Apps Script のソースは、Apps Script API の projects.getContent で取り出せます。 公式のリファレンスでは、GET https://script.googleapis.com/v1/projects/{scriptId}/content でスクリプトのプロジェクトの中身を返し、返る files の一覧のうち1つは必ず「appsscript」という名前の JSON のマニフェストとされています。必要な OAuth のスコープは script.projects か script.projects.readonly のどちらかで、点検には読み取りだけの script.projects.readonly を使います。 versionNumber を付けなければ HEAD の版が返ります。

取り出したファイルには、名前、種類、中身、最後に直した人、直した日時が付いています。 File のリファレンスでは、type は SERVER_JS(サーバー側のコード)、HTML、JSON(マニフェストだけ)のいずれかで、source がファイルの中身、lastModifyUser と updateTime が最後の変更とされています。updateTime を台帳の点検の日付と比べれば、点検の後に変更されたスクリプトが分かります。 第3章の(c)の事故は、ここで拾えました。

判定は、Claude API の構造化出力で受け取ります。 公式のドキュメントでは、output_config.format に type: "json_schema" とスキーマを渡す形で、Claude API では一般提供(GA)とされています。返ってくる JSON の形が決まるので、点検の一覧に機械的に書けます。

03どうやって実装するのか

Step1

処理の起点を決める

毎月1日の定時に動かします。 点検の対象は、台帳から次の3つを抜き出して決めます。

対象抜き出し方
新しく登録されたもの台帳の登録日が先月のもの
変更されたものPython はリポジトリの最終の変更日、Apps Script は updateTime が前回の点検の日より新しいもの
定期の見直しの番が来たもの前回の点検から11か月を超えたもの

2行目が、これまでの点検に無かったものです。 登録のときだけ読む運用では、登録の後の変更が点検されません。 毎月、変更の日付と点検の日付を比べることで、変更されたスクリプトが必ず翌月の点検に入ります。

定時に一括で動かすのは、急ぎの業務ではないためです。 点検の結果は月の初めの数日で担当者が確かめ、持ち主に返します。新しく登録されたものをすぐに見たいときは、台帳の登録をきっかけに1本だけ動かす経路も作れます。

Step2

入力データを集める

データ中身取得元
ソースPython のファイル、Apps Script の SERVER_JS と HTML のファイルリポジトリ/Apps Script API
マニフェストApps Script の appsscript.json(権限のスコープ)Apps Script API
解析の結果Bandit の検出(テストの番号、行、重さ、確かさ)Bandit の JSON 出力
文字列の検索の結果キー・トークンらしい文字列の行収集のプログラム
台帳の情報スクリプトの目的、持ち主、使うデータ、動かす頻度登録の台帳
観点の表8つの観点、該当の例、直し方の決まり情報システム部が作る

質を決めるのは、台帳の目的の欄です。 同じ「表の全行を消す」処理でも、毎朝作り直す集計用の表なら問題がなく、受注の台帳なら重大です。 目的が分からなければ、AIは書き方だけで判定することになり、該当なしと重いの区別が付きません。

Bandit は、Python のソースを解析して危ない書き方を探すツールです。 公式のドキュメントでは、Bandit は各ファイルを処理して AST(構文の木)を作り、その節に対して該当するプラグインを動かし、全部のファイルを見終えたら報告を出すとされています。報告の形には JSON や SARIF などがあります。この構成で特に使うのは、次の検出です。

Bandit のテスト内容対応する観点
B105/B106パスワードらしい文字列の直書き、関数の引数への直書き① 認証情報の直書き
B110/B112例外を受けて pass、continue だけをする③ 例外の握りつぶし
B113タイムアウトを付けない通信⑧ 終わらない繰り返し
B501証明書の検証を無効にした通信⑦ 通信の検証の無効化
B602shell=True でのコマンドの実行② 全件の削除・上書き(コマンドの組み立てによる)

Apps Script には Bandit が使えないので、文字列の検索とAIの判定だけで見ます。 その分、Apps Script の判定は「判断できない」に倒れやすくしておきます。

Step3

データの取得方法を決める

Python のソースは、社内のリポジトリから台帳に登録された置き場所のファイルを取り出します。 取り出したら Bandit を報告の形を JSON にして動かし、結果を受け取ります。

Apps Script のソースは、台帳に登録されたスクリプトのIDで projects.getContent を呼びます。 呼び出しには、点検用のアカウントに各プロジェクトを読む権限が要ります。部署が作ったプロジェクトを、点検用のアカウントに閲覧者として共有してもらうことを、登録の決まりに加えます。

取るものどこから何に使うか
files[].source(SERVER_JS)projects.getContent判定するソース
files[].source(JSON のマニフェスト)projects.getContentoauthScopes から権限の広さを見る
files[].updateTimeprojects.getContent点検の後に変更されたかを見る
files[].lastModifyUserprojects.getContent台帳の持ち主と違う人が直したかを見る
Bandit の resultsBandit の JSON 出力行ごとの検出

4行目の「最後に直した人」は、持ち主が異動した後に別の人が直しているスクリプトを見つけるのに使います。 台帳の持ち主と違う人が直していれば、台帳の更新が漏れているか、引き継ぎができていない合図です。

取り出したソースは、点検のあいだだけ情報システム部の作業用の場所に置きます。 部署のフォルダやリポジトリに、点検の結果を書き戻すことはしません。

Step4

AIへ渡す前に整形する

  1. 台帳とソースの対応を確かめる … 台帳の置き場所にファイルが無いもの、IDで取り出せないものは「取り出せない」として一覧に残します
  2. キー・トークンらしい文字列を伏せる … 検索で見つかった値は、AIに渡す前に *MASKED* に置き換え、行番号だけを残します
  3. 長いソースを分ける … 1,000行を超えるものは、関数やファイルの単位で分けて判定させ、結果を合わせます
  4. マニフェストの権限を一覧にする … oauthScopes を取り出し、Drive やメールの全体に及ぶスコープに印を付けます
  5. Bandit の結果を行番号でソースに結び付ける … AIが「この行の検出」として読めるようにします
  6. 前回の点検の結果を付ける … 前回の指摘が直っているかを見るため

2番目を省かないでください。 認証情報の直書きを探すために、直書きされたキーそのものを外部のAPIに送ることになっては本末転倒です。 値は伏せ、「この行に直書きがある」という事実だけを渡します。

4番目の権限の広さは、Apps Script で特に効きます。 受注の表を1枚だけ読むスクリプトが、Drive の全ファイルを読み書きできる権限を持っていることがあります。 動いているうちは問題になりませんが、乗っ取られたときの被害の範囲が変わります。

Step5

AIに処理させる

させるのは、8つの観点それぞれについて、該当するか、どの行か、重さはどうか、どう直すかを判定することだけです。

観点判定の仕方判断できないときの扱い
① 認証情報の直書き伏せた値の行と Bandit の B105/B106 を見て、本当に認証情報か値が伏せられていて種類が分からなければ「判断できない」
② 全件の削除・上書き削除・上書き・ゴミ箱への移動に、件数の上限か確認があるか対象の表が何か分からなければ、台帳の目的で見る
③ 例外の握りつぶし例外を受けて何も記録せずに続けるかログに残していれば該当なし
④ 外部への送信先社外のURLやメールへの送信があるか、台帳の使うデータと合うか送信先が社内か社外か分からなければ「判断できない」
⑤ 権限の広さマニフェストのスコープが処理に対して広すぎないかPython は対象外
⑥ 宛先の直書きメールアドレスや表のIDがソースに直書きされているか-
⑦ 通信の検証の無効化証明書の検証を切っているか-
⑧ 終わらない繰り返しタイムアウトや回数の上限の無い待ちや繰り返しがあるか上限が別の関数にあるかもしれなければ「注意」

重さは3段階で返させます。 「重い」は、そのままでは情報の漏えいかデータの消失につながるもの。「注意」は、条件しだいで問題になるもの。「該当なし」。重さの基準は観点の表に書いておき、AIに独自の基準を作らせません。

させないこと理由
ソースを書き換えて返す直すのは持ち主。直したソースを渡すと、確かめずに貼り付ける
8つ以外の観点で指摘する指摘が増えすぎ、持ち主が何から直すか分からなくなる
スクリプトを止めるべきかを判断する止めるかは業務への影響を見て、情報システム部と部署が決める
伏せた値を推測する値は不要。行と種類だけでよい
書き方のよしあしを論じる点検の目的は危ない書き方を見つけることで、コードの品質の評価ではない

2行目がいちばん起きやすい失敗です。 AIはソースを読むと、変数の名前の付け方や関数の分け方まで指摘したくなります。指摘が20件並ぶと、持ち主は大事な1件を見落とします。 観点を8つに固定し、それ以外は書かせません。

Step6

指示内容を固定する

あなたは情報システム部の担当として、社内の部署が作った業務用スクリプトに
危ない書き方が無いかを点検する立場です。下の8つの観点だけで判定してください。

【観点】
1. 認証情報の直書き(パスワード、APIキー、トークン)
2. 全件の削除・上書き(件数の上限や確認の無い削除、上書き、ゴミ箱への移動)
3. 例外の握りつぶし(例外を受けて記録せずに続ける)
4. 外部への送信先(社外のURL・メールへの送信)
5. 権限の広さ(Apps Script のマニフェストのスコープが処理に対して広い)
6. 宛先の直書き(メールアドレス、表やフォルダのID)
7. 通信の検証の無効化(証明書の検証を切る)
8. 終わらない繰り返し(タイムアウトや回数の上限の無い待ち・繰り返し)

【重さの基準】
- high:そのままでは情報の漏えいかデータの消失につながる
- medium:条件しだいで問題になる
- none:該当しない
- unknown:与えられた情報だけでは判断できない
迷ったときに none を選ばないでください。

【厳守事項】
- 8つの観点以外の指摘をしないでください。変数名や書き方の好みに触れないでください。
- ***MASKED*** の値を推測しないでください。
- ソースを書き換えたコードを返さないでください。直し方は文で、1件2文以内で書いてください。
- 直し方は【直し方の決まり】に沿ってください。
  (例:Apps Script の認証情報はスクリプトのプロパティに置く。Python は環境変数か社内の秘密情報の置き場所)
- 該当する行は、ソースの行番号で示してください。推測の行番号を書かないでください。
- 台帳の目的から見て、削除や上書きが意図どおりと読めるときも、件数の上限や確認が無ければ medium にしてください。
- スクリプトを止めるべきかは書かないでください。

【台帳の情報】{purpose, owner, data_used, frequency}
【解析の結果】{bandit_results}
【マニフェストの権限】{oauth_scopes}
【前回の指摘】{previous_findings}
【ソース(行番号付き)】{source}

「迷ったときに none を選ばない」を明記しないと、AIは該当なしに寄ります。 ソースの一部しか見えないとき、「問題は見当たりません」と書くのがAIにとって最も無難だからです。 unknown を選ばせて人に回すほうが、見落としより安全です。

「意図どおりと読めても上限が無ければ medium」を入れるのは、第3章の(c)のためです。 「出荷済みの行を消す」処理は、意図どおりの削除に見えます。問題は、条件を取り違えたときに全行が消えることです。 件数の上限か確認があるかで見させます。

Step7

出力形式を固定する

構造化出力で、次の形の JSON を受け取ります。

{
  "script_id": "",
  "language": "python | apps_script",
  "findings": [
    {
      "aspect": "hardcoded_secret | mass_delete | swallowed_exception | external_send | broad_scope | hardcoded_target | tls_disabled | unbounded_loop",
      "severity": "high | medium | none | unknown",
      "lines": [0],
      "evidence": "",
      "fix": ""
    }
  ],
  "previous_findings_resolved": ["mass_delete"],
  "note_for_reviewer": ""
}

findings には、8つの観点のそれぞれを必ず1つずつ並べさせます。 該当しない観点も none として返させ、観点を飛ばしていないことを形で確かめます。 8個そろっていない結果は、人に回します。

1つ目の理由は、点検の一覧に機械的に書けることです。 severity が high か unknown のものだけを担当者の確認待ちにし、medium は持ち主への連絡の下書きに回し、すべて none のものは点検済みにします。

2つ目は、スキーマの制約に合わせられることです。 公式のドキュメントでは、構造化出力は数値の範囲や文字列の長さの制約、minItems が0か1を超える配列の制約に対応しておらず、additionalProperties は false にする必要があるとされています。8個そろっているかはスキーマでは強制できないので、受け取った後のプログラムで数えます。 拒否や max_tokens での打ち切りのときは形どおりに返らないことがあるとされているので、その場合も人に回します。

3つ目は、previous_findings_resolved で前回の指摘が直ったかを追えることです。 前回 high だった観点が今回 none になっていれば、直ったと読めます。

Step8

システムへ連携する

つなぎ先方式内容
スクリプトの登録の台帳収集のプログラムが読む今月の対象、目的、持ち主
社内のリポジトリ収集のプログラムが読むPython のソース
Apps Script APIprojects.getContent(読み取りのスコープ)Apps Script のソース、マニフェスト、変更日
Bandit収集のプログラムが動かすPython の解析の結果(JSON)
Claude APIAPI呼び出し(構造化出力)8つの観点の判定
点検の一覧収集のプログラムが書く判定の結果と確認待ちの印

部署のスクリプトとリポジトリには、何も書き込みません。 点検用のアカウントは読み取りだけの権限で動かします。点検の仕組みそのものが全部のスクリプトを書き換えられる権限を持つと、今度は点検の仕組みが最も危ないスクリプトになります。

Step9

人が確認する

  1. unknown を先に見る … 多くは、ソースが分かれていて上限や確認が別の場所にあるもの
  2. high を確かめる … evidence と行番号でソースを開き、本当に該当するかを見ます
  3. 持ち主への連絡を送る … AIの fix を下書きに、担当者が直して送ります。送るのは担当者です
  4. 重いものは持ち主の上長にも知らせる … 認証情報の直書きと、確認の無い全件の削除
  5. 判定を覆したら記録する … どの観点を、どちらに変えたか

目標は、120本をならして1本6分です。 すべて none のスクリプトは一覧で流し見て、high と unknown のものに時間を使います。 該当の多い月は6分を超えます。

Step10

例外に対処する

起きること対応
台帳の置き場所にファイルが無い/IDで取り出せない「取り出せない」として一覧に残し、持ち主に置き場所を確かめる
Apps Script のプロジェクトが点検用のアカウントに共有されていない持ち主に共有を頼む。共有されるまで点検済みにしない
findings が8個そろっていない人に回す。作り直しを1回だけ試す
拒否や打ち切りで形どおりに返らない人に回す
1,000行を超えて分けたソースで、判定が食い違う重いほうを採り、人に回す
外部のライブラリの中に危ない書き方があるこの構成の対象外。社内で書いた部分だけを判定する
持ち主が退職・異動している部署の上長に持ち主の付け替えを頼み、台帳を直す

上から2行目までが大半を占めます。 どちらもAIの問題ではなく、台帳と共有の整備の問題です。 最初の数か月は、点検より台帳の整備に時間がかかります。

Step11

記録を残す

  • 点検した日、対象のスクリプトと版(Apps Script は updateTime、Python はリポジトリの版)
  • Bandit の JSON 出力と、文字列の検索の結果(値は伏せたもの)
  • Claude API が返した JSON の全文
  • 人が判定を覆した記録 … どの観点を、どちらに変えたか
  • 持ち主へ送った連絡と、直った版
  • 観点ごと・部署ごとの high の件数(月ごと)

最後の行は、研修の題材を選ぶのに使います。 特定の部署で認証情報の直書きが続くなら、その部署向けにスクリプトのプロパティの使い方を教えるほうが、1本ずつ指摘するより早く減ります。

04実装レベルの3段階

最小構成:手でソースを貼り、8つの観点で判定させる / 1本ずつの判定
半自動化:上記+毎月1日に台帳から対象を選び、ソースの取り出し、Bandit、Claude API の判定、一覧への書き込みまでを動かす / 収集と判定と一覧化
本格構成:上記+リポジトリへの変更や Apps Script の変更をきっかけにその都度点検し、持ち主への連絡の下書きを自動で用意する / 変更のたびの点検と連絡の下書き

本記事が想定するのは半自動化です。 1本30分が6分になるのは、この段階です。読む20分が、判定の結果を確かめる時間に置き換わります。 本格構成で変わるのは、点検の時期です。 月に1回ではなく、変更のたびに点検されます。第3章の(c)のような「点検の後の変更」の事故を、翌月まで待たずに止められます。 ただし、変更をきっかけにする仕組みは置き場所ごとに作る必要があり、開発の手間が増えます。

05工数削減シミュレーション

前提値(モデル条件)
対象人数
2 名
月間件数
120 件
1件あたり現在時間
30 分
1件あたり導入後時間
6 分
現在  120件 × 30分 ÷ 60 = 60 時間/月
導入後 120件 × 6分 ÷ 60 = 12 時間/月
月間削減時間
48h
削減率
80%
年間削減時間
576h
年間金額換算(時間単価4,500円)
259万円
モデル条件による試算であり、実際の効果は業務内容・運用方法によって異なります。

自社条件で導入効果を整理したい方へ

このユースケースを自社に当てはめた場合の前提値と削減見込みを、業務ヒアリングをもとに整理します。

AI活用について相談する

06向いている企業・向いていない企業

向いている
  1. 現場の部署が Python や Google Apps Script で業務の小さな自動化を作るようになり、登録されたスクリプトが数百本ある会社。情報システム部門が全部を読む人手が無く、APIキーやパスワードの直書き、確認なしの全件削除が見つかるのは事故の後になっている場合。スクリプトの登録の台帳と置き場所(共有フォルダやリポジトリ、Apps Script のプロジェクト)がすでに決まっている場合。
向いていない
  1. スクリプトが数十本で、情報システム部門が変更のたびに目で読めている場合。業務のプログラムをすべて開発会社が作り、コードレビューの手順がすでにある場合。スクリプトの置き場所がばらばらで、どこに何本あるかが分からない場合(先に台帳づくりが要る)。なお、そのスクリプトを使い続けてよいかの判断、業務への影響の評価、脆弱性の診断は、この構成では代替できません。

07最小構成で試す方法

  1. 登録済みのスクリプトから10本を選ぶ(うち数本は、過去に指摘して直したものの直す前の版を入れる)
  2. 認証情報らしい値を手で伏せる
  3. 手元のAIサービスの画面に、第7章の観点と重さの基準と一緒に1本ずつ貼る
  4. 返ってきた判定を、過去の指摘と見比べる

10本は必ずやってください。 収集の仕組みを作る前に、8つの観点で判定できるか、指摘が増えすぎないかを確かめます。

出てきた内容判断
過去に指摘したものと同じ観点が high で出た収集とAPIの呼び出しに進む
8つ以外の指摘が混ざる指示の書き方で直る。構成は有効
unknown が多い台帳の目的の欄が足りない。台帳の整備が先

3行目が出ることは珍しくありません。 目的が「業務の効率化」とだけ書かれた台帳では、削除が意図どおりかをAIも人も判断できません。 何の表を、何のために、どの頻度で触るのかを書いてもらう決まりにします。

08実装時につまずきやすいポイント

問題対策
直書きのキーをそのままAPIに送ってしまう文字列の検索で見つけた値を伏せてから渡す
AIが該当なしに寄る迷ったら unknown を選ばせ、人に回す
8つ以外の指摘が増える観点を固定し、指示に「触れない」と書く
観点を飛ばした結果が返る8個そろっているかをプログラムで数える。スキーマでは強制できない
意図どおりの削除を見逃す件数の上限か確認が無ければ medium にする
Apps Script のプロジェクトが取り出せない点検用のアカウントへの共有を登録の決まりにする
点検の後の変更が見られない変更日と点検日を比べ、変更されたものを毎月の対象に入れる
点検用のアカウントの権限が広すぎるscript.projects.readonly など読み取りだけのスコープにする
AIが直したソースを返す直し方は文で、2文以内にさせる
指摘が自動で持ち主に飛ぶ担当者が確かめてから送る

上の2行が、この構成の失敗のほとんどです。 1行目は点検のために秘密を外へ出してしまう失敗、2行目は見落としを「該当なし」として記録してしまう失敗です。どちらも、点検をしたつもりで安全が下がる形で起きます。

09セキュリティ・AIガバナンス上の注意点

この構成で扱うデータ: 部署のスクリプトのソース、その中にある社内のシステムの接続先、表やフォルダのID、メールアドレス、そして直書きされた認証情報です。

  1. 認証情報の値を外へ出さない … 文字列の検索で見つけた値は伏せてから API に渡します。検索で見つからなかった直書きは、そのまま送られる可能性があることを前提にし、API の利用の条件を確かめておきます
  2. 点検の権限を読み取りに限る … Apps Script API は script.projects.readonly、リポジトリも読み取りだけにします
  3. 秘密の置き場所の決まりを先に作る … Apps Script のスクリプトのプロパティは、公式のガイドで「開発者の外部データベースのユーザー名とパスワード」のようなアプリ全体の設定の置き場所の例とされています。ただし、ガイドには値の暗号化や保護についての記載はありません。どの秘密をどこに置くかは、情報システム部が決まりとして示します
  4. この構成は脆弱性の診断を代替しません … 8つの観点は、部署のスクリプトでよく起きる危ない書き方に絞ったものです。外部に公開するシステムや個人情報を大量に扱う処理は、別に診断を受けます
  5. 止めるかどうかは人が決める … high が出ても、スクリプトを止めるかは業務への影響を見て情報システム部と部署が決めます
  6. 持ち主を責める道具にしない … 指摘の件数を人事の評価に使いません。部署のスクリプトづくりを続けてもらうことが、そもそもの目的です

誤りが起きた場合のリスクは、危ない書き方を見落とすことと、点検のために秘密を外へ出すことの2つです。 前者は unknown に倒す指示と8個の数の確認で、後者は値を伏せる前処理で防ぎます。

10まず何から始めるか

1週目:観点の表と直し方の決まりを作る

8つの観点ごとに、該当する例、重さの基準、直し方の決まりを1枚にまとめます。Apps Script はスクリプトのプロパティ、Python は環境変数か秘密情報の置き場所、のように、置き場所の決まりもここで決めます。

2週目:10本で試す

過去に指摘したことのあるスクリプトを含む10本で、第8章の手順を試します。AIが過去の指摘と同じ観点を拾うか、8つ以外の指摘が増えないかを最優先で見ます。

3週目:台帳と共有を整える

台帳の目的の欄を書き直してもらい、Apps Script のプロジェクトを点検用のアカウントに共有してもらいます。 共有されていないものの一覧を部署ごとに出します。

4週目:収集のプログラムを作る

台帳を読み、ソースを取り出し、Bandit を動かし、Claude API で判定して一覧に書くところまでを作ります。この時点では持ち主への連絡は手で送り、判定の当たり外れを記録します。

2か月目: 毎月1日の定時実行に切り替え、high と unknown の件数を数えます。3か月目以降: 1本30分が何分になったかを実測し、部署ごとの high の件数を研修の題材に使います。unknown が全体の1割を切り、点検の後の変更が毎月必ず点検に入るようになった時点で、この構成は完成です。


11関連ユースケース

12この仕組みを理解するための記事

13技術仕様の確認日・参考情報

技術仕様確認日:2026-10-12/最終更新:2026-10-13
確認した内容情報源確認日
構造化出力が output_config.format に type: "json_schema" とスキーマを渡す形であり、Claude API で一般提供(GA)であること。数値の範囲、文字列の長さ、minItems が0か1を超える配列の制約に対応せず、additionalProperties は false が必要なこと。拒否や max_tokens の打ち切りで形どおりに返らないことがあることClaude API ドキュメント: Structured outputs2026-10-12
GET https://script.googleapis.com/v1/projects/{scriptId}/content でプロジェクトの中身を返すこと。files のうち1つが「appsscript」という名前の JSON のマニフェストであること。スコープが script.projects か script.projects.readonly であること。versionNumber を付けなければ HEAD が返ることApps Script API: projects.getContent2026-10-12
File に name、type、source、lastModifyUser、updateTime があること。type が SERVER_JS、HTML、JSON(マニフェストのみ)であることApps Script API: File2026-10-12
スクリプトのプロパティが、開発者の外部データベースのユーザー名とパスワードのようなアプリ全体の設定に使われるとされていること。値の暗号化や保護の記載が無いことApps Script: Properties Service2026-10-12
Bandit が Python のコードのよくあるセキュリティの問題を探すツールで、各ファイルの AST を作ってプラグインを動かし、報告を出すことBandit documentation2026-10-12
B105/B106(パスワードの直書き)、B110/B112(try-except-pass/continue)、B113(タイムアウトの無い通信)、B501(証明書の検証の無効化)、B602(shell=True)のテストがあることBandit: Test Plugins2026-10-12
報告の形に csv、html、json、sarif、text、xml、yaml などがあることBandit: Report Formatters2026-10-12

スクリプトを使い続けてよいか、止めるかは、自社の情報システム部と部署が業務への影響を見て判断してください。 本記事の8つの観点は構成の例であり、脆弱性の診断に代わるものではありません。

実装ステータス:構成例。 公開仕様に基づいて設計した構成であり、当社で実際に構築・検証したものではありません。工数の数値はモデル条件による試算です。

自社の業務に使えるAI活用候補を整理します

このユースケース(UC-1282)についてのご相談はこちらから。

AI活用について相談する
目次