技術レポート:AI の「コード実行」から、本番の鍵のほぼすべてが抜かれるまで
株式会社イネブラ(teai の運営会社)/掲載 2026年11月9日/時刻は日本時間
お客様へ(先にお読みください)
このレポートは技術者向けです。お客様へのお願いと、読まれたおそれがある情報のくわしい説明は、お知らせにまとめています。要点は次のとおりです。
読まれたおそれがある情報
- teai に登録しているすべての方(最大 2,536人)の、名前とメールアドレス、利用の記録、パスワード(そのままの形では保存していません。パスワードでログインする69人のうち、旧方式で保存されていた47人の方は、漏れた鍵と組み合わせると推測されやすくなります。残り22人の方は、今はより強い方式で保存していますが、いつから替わっていたかを確認中のため、同じく推測されやすいものとして扱います。69人全員に個別にもお知らせします)、一部の方の会話と AI の記憶、サポートへのお問い合わせの内容。データベースの複製は、持ち出されたものとして扱っています。
- 決済会社(Stripe)に当社が預けている情報:お名前・メールアドレス・請求先と配送先の住所・電話番号(入力がある方のみ)・カードの種類と下4桁・有効期限・決済の履歴。teai 以外の当社のサービスのお客様も含みます。カード番号の全体は、当社には保存していません。
- 当社のサービスから送ったメールの宛先・件名・本文。
- 当社がクラウド(Cloudflare)に保存していたデータも読み出されました。そこにお客様の情報が含まれていたかは、確認しています。
実際にどこまで読まれたかは、調べています。
お願いしたいこと
- メールアドレスとパスワードでログインしている方は、teai.io をご自分で開き、パスワードを再設定してください。同じパスワードをほかで使っていれば、そちらも変えてください。
- teai に他社の API キーを登録したことがある方は、各社で作り直してください(11月9日の集計では、お客様が登録したキーは0件でした)。
- Sente・te や teai の API をお使いの方は、teai.io/keys で API キーを作り直し、古いキーを削除してください。11月9日17時10分より前からあるキーは、11月21日に当社がすべて使えなくします。
- 当社を名乗るメールのリンクは開かないでください。
現時点で確認できていること
- teai が発行した API キーは、元に戻せない形で保存しています。ただし、攻撃者はデータベースに書き込めたため、偽のキーを足した可能性を否定できません。そのため、上の3のとおり、11月21日に一括で使えなくします。
- GitHub のリポジトリと CI に、改ざんは見た範囲では見つかっていません(一部の設定変更は照合中)。te のインストーラはリポジトリの中身と一致しました(SHA-256 で照合)。Sente 本体の照合は続けています。
- お客様のお支払いに不審な返金はなく、入金先の口座も変わっていません(攻撃者の決済23件は、当社が返金したものです)。
- 安全のため、すべての方のウェブのログイン状態を解除しました。もう一度ログインしてください。
問い合わせ先:teai.io/contact
要約
- teai のチャットの AI には、シェルを動かす道具(code_execute)がありました。この道具は、サービス本体と同じマシン上で root として動いていました。利用者は AI に頼む形で、本体プロセスの環境変数を読み出せました。環境変数には、本番のほぼすべての秘密の鍵(約100個)が入っていました。
- 期間:2026-09-08 〜 2026-11-09(当社が発見)。約2か月です。
- 読み出された鍵で、次のことが起きました。
- データベースを直接読み書きできる状態になった
- 代表アカウントを乗っ取られた
- バックアップの保管庫へ書き込まれた(持ち出しを前提に扱う)
- 当社ドメインから詐欺メール約7.6万通を送られた
- 利用枠を不正に付与された
- 根本原因
- 隔離のない実行環境
- 鍵を1か所に集め、強い鍵を共用していたこと
- 防御を AI の判断に頼り、外部サービス側の異常を見ていなかったこと
1. 構成(当時)
- Rust(axum)の単一バイナリを Fly.io の VM 群で動かし、データは Turso(libSQL)に置いていました。バックアップは Litestream で S3 に複製していました。
- 秘密の鍵は Fly の secrets として、本体プロセスの環境変数に入っていました。データベース、メール送信、決済、AI 各社、クラウド、管理用 API、データ暗号用のマスター鍵、パスワード照合用の鍵まで含みます。
- チャットの AI は50種類以上の道具を使え、その1つが code_execute でした。
code_execute の作り(当時)
- 実行場所:本体と同じ VM。ユーザーは本体と同じ root でした。
- 入れていた対策:子プロセスの環境変数を空にする、作業ディレクトリを利用者ごとに分ける、時間制限を設ける。
- 抜けていた対策
- プロセスの名前空間の分離
/procの制限(hidepid)- 別ユーザーでの実行
- 読み取り専用のファイルシステム
- 外向き通信の制限
- 結果:子プロセスの環境変数は空でしたが、
/procから本体プロセスの環境変数が読めました。永続ボリューム(/data)も読み書きできました。 - 出力をそのまま画面へ流していました。 道具の出力は最大約6,000文字まで AI に渡り、先頭500文字は利用者の画面にもそのまま表示されました。AI が要約を断っても、利用者は生の出力を受け取れました。
- 危険な依頼を断る役目は、事実上 AI の判断だけでした。攻撃者は正当な作業を装い、出力を符号化して、AI の判断をすり抜けました。
2. 攻撃の流れ(確認できた事実)
アカウントは記号で示します(A〜F)。
| 日時(JST) | 誰が | 起きたこと |
|---|---|---|
| 9/8〜 | A(実在しないドメインのメールで登録した4件) | code_execute でサーバーの中を調べた |
| 9/21 | B | 本体の環境変数を取得。管理用の鍵で自分に20万クレジットを付与。/data に目印のファイルを置いた |
| 9/22 00:24 | (外部) | 漏れたクラウドの鍵で、バックアップの保管庫(S3)に目印のファイルを書き込んだ |
| 9/22〜11/7 | (外部の約10の IP) | 漏れたクラウドの鍵で、権限を一斉に確かめた。S3 の1バケットへの書き込みは成功した。読み出しも権限上はできたが、記録がないため持ち出されたものとして扱う。ほかの操作は拒否された |
| 9/25 | — | AI 利用(OpenRouter)の鍵の値を取得 |
| 9/27 16:33 | C | 代表のメールアドレスでパスワードを5回試した(すべて失敗) |
| 9/27 16:41 | C | 漏れたデータベースの鍵で、代表アカウントの偽のログイン情報(期限 2027-12-31)を直接書き込んだ。代表アカウントで API キーを作り、50万クレジットを付与した |
| 9/27〜 | C(代表として) | 環境変数の全文を取得。データ暗号の鍵、パスワード照合の鍵、管理用の鍵が含まれる。当社がクラウド(Cloudflare)に保存していたデータ(KV)も読み出された(お客様の情報が含まれていたかは確認中) |
| 9/28 | — | サーバー上で SSH サーバーと端末共有ツール(tmate)を起動された。外から実際に接続できたかは不明。同じ日に、設定だけを変えたリリース(v1407)がある(自社の操作かを照合中) |
| 10/12〜11/9 16:48 | (外部から直接) | 自社6ドメインを差出人に、詐欺メール 75,964 通。使われた鍵は、teai の鍵だけとは限らない(teai の鍵を消したあとも、同じメール送信のアカウントにあった、ほかの鍵で送られていた) |
| 11/3・11/7 | D・E | 同じ手口で環境変数を取得 |
| 11/9 | — | 当社が、AI 利用残高の不具合の調査中に、データベースの記録から発見 |
| 11/9 | F | 隔離のあと、同じ系統の使い捨てアドレスで2回再登録した(13:32・15:20。いずれも利用なし。隔離済み)。同じ日、攻撃者は同じカードで、別の決済画面を使ったとみられる購入を再び試みた(決済会社の不正検知で拒否) |
攻撃者がデータベースに直接書き込んだもの:偽のログイン情報1件と、作業用の表1つ(発見時は空)です(API キーの作成と利用枠の付与は、アプリの機能を通じた操作です)。見た範囲では、お客様のデータが書き換えられた形跡はありません。全件の照合はまだ終わっていません。
お金の動き
- E が、1枚の Amex で23件・計 ¥392,350 を購入しました。盗難カードの疑いがあるため、11/9 に当社からカードへ全額を返金し、攻撃者の定期購読も解約しました。
- D は、3D セキュア認証済みの Visa 2枚で、計 ¥7,850 を購入しました。
- AI 利用料:10/29 に記録していた残高と比べて、それ以降に使われた約 $6,900 のうち、約 $4,925 の使い道が分かっていません。9/25 に漏れた鍵で使われたおそれがあり、調べています。
- お客様のお支払いに不審な返金はなく、入金先の口座も変わっていません(攻撃者の決済23件は、当社が返金したものです)。
3. なぜ防げなかったか
- 隔離の単位を誤った:子プロセスの環境変数を消すことを、隔離だと考えていました。同じマシン・同じユーザーである限り、
/procから本体が見えます。 - 生の出力を利用者に見せた:AI の判断とは別に、道具の出力がそのまま画面へ流れていました。
- AI を防御に数えた:AI はだまされます。防御は、権限・ネットワーク・ファイルシステムの側に置くべきでした。
- 鍵を1か所に集め、強い鍵を共用した
- 全部の鍵が、本体の環境変数に平文で並んでいました。
- メール送信は全権限の鍵を複数のサービスで、決済の鍵は当社のアプリ25と Worker 5つで共用していました(配布用の一覧には、そのうちアプリ14しか載っていませんでした)。
- 管理者の権限を、チャットにも持たせていた:利用者のチャットでは、道具の出力は画面に先頭500文字しか出ません。攻撃者が代表アカウントを乗っ取ったのは、代表のチャットでは管理者だけが使える道具も使え、環境変数の全文を受け取れたためとみられます。人の管理画面の権限と、AI に持たせる権限を分けていませんでした。
- ログイン情報を平文で保存していた:データベースの鍵を持つ者が、任意のログイン情報を書き込めました。乗っ取りの直接の原因です。
- 古いパスワードを残していた:8月に遅いハッシュ(argon2)へ切り替えていましたが、移行は「次にログインしたとき」だけでした。パスワードを持つ69人のうち、ログインしていない47人のパスワードは、秘密の鍵を加えた速いハッシュ(旧方式)のまま残り、その鍵が漏れました。
- 登録と付与の悪用に気づけなかった:実在しないドメインや使い捨てのアドレスで登録できました。20万・50万クレジットの付与にも警報がありませんでした。
- 外を見ていなかった:次の異常に見張りがなく、約1か月気づけませんでした。
- 詐欺メールの送信数と苦情率
- AI の利用料
- クラウドの権限エラーの急増
- 外向きの通信(tmate は外へつなぐ道具です)
4. ご自身の環境で確かめてほしいこと
AI に道具を持たせているサービスを作っている方へ。検証用の環境で確かめてください(本番では試さないでください)。
- AI の道具の中で
idを実行すると、root になっていませんか。 - 道具の中から、自分以外のプロセスが見えませんか(
psで、本体のプロセスが見えたら隔離が足りません)。 - 道具の中から、外へ通信できませんか。
- 道具の実行環境に、本番の鍵が1つでも入っていませんか。
- 道具の出力を、検査せずに利用者へ返していませんか(秘密らしい文字列の検出)。
- ログイン情報(セッション)と API キーは、ハッシュで保存していますか。
- パスワードの保存方式を変えたとき、古い方式のまま残っている人を、強制的に移行していますか。
- データベースの鍵は、読み書きの1本だけになっていませんか(読み取り専用の鍵と分けていますか)。
- 鍵を入れ替えるとき、新しい鍵で実際に接続できること、古い鍵を使っている所が残っていないことを確かめてから、古い鍵を無効にしていますか(当社はこの2点で、自分たちの作業でサービスを止めました)。
- 外部サービスの鍵は、サービスごと・用途ごとに分け、必要な権限だけにしていますか。
- 外部サービス側の異常(送信数、苦情率、利用料、権限エラー)を見張っていますか。
隔離の手段としては、microVM(Firecracker など)、gVisor、少なくともプロセス名前空間の分離と hidepid=2、そして別ユーザーでの実行があります。
5. 対応と再発防止
| 対策 | 状態 |
|---|---|
| code_execute ほか、サーバー上でコマンドやファイル操作をする道具を、既定で無効にする | 実装・本番反映済み(11/9) |
| 道具の出力から秘密を自動で消す(値そのもの・16進数・base64・鍵らしい形) | 実装・本番反映済み(11/9) |
| サーバーの状態や設定を返す道具を AI から外す | 実装・本番反映済み(11/9) |
| 関わった13アカウントの隔離と、API キー・ログインの失効(表の A〜F のほか、登録元や使い方から同じ系統と判断したものを含む) | 済(11/9) |
| 代表アカウントの偽のログイン情報と、攻撃者が作ったキーの削除 | 済(11/9) |
| データベースの鍵の入れ替え(旧鍵はすべて無効) | 済(11/9 17:10) |
| データ暗号の鍵の入れ替えと再暗号化 | 済(11/9) |
| 管理用の鍵・AWS の鍵の入れ替え | 済(11/9) |
| メール送信の鍵:全削除し、アプリごとの送信専用の鍵へ | 済(11/9 17:36)。以後の詐欺メールがないことを 11/9 17:37 と、22時台(送信の一覧の直近分)に確認 |
| ログイン情報のハッシュ保存と、すべてのウェブのログイン状態の解除 | 実装・本番反映済み。解除も実行し、0件を確認(11/9) |
| 決済の鍵 | 済(11/9。全サービスで新しい鍵が使えることを確認) |
| Cloudflare・RunPod・Google・LINE・AI 各社の鍵 | 一部済(11/9 に Cloudflare のグローバル鍵と、OpenRouter・Google の AI の鍵を入れ替え、古い鍵を削除)。ほかは作業中 |
| 本番マシンの作り直し、または置かれた仕組みの残存確認 | 確認中 |
| 旧方式の47人に再設定をお願いし、旧方式ではログインできないようにする(パスワードを持つ69人全員にも念のためお願いする。再設定すると argon2 に移る) | 再設定の仕組みは本番反映済み。旧方式でのログインを止める変更:済(11/9 の本番反映。本番で 403 を確認)。個別のご案内は、これから送ります |
| 漏れた GitHub トークン | 11/9 の時点ですでに無効(いつ無効になったかは確認中)。攻撃の期間中に悪用された形跡は、見た範囲では見つかっていない |
| AI 利用料の使途不明分(約 $4,925)の調査 | 調査中。11/14に報告 |
| 代表アカウントの連携トークン10件の再発行 | 作業中 |
| 9/28 の設定だけのリリース(v1407)が当社の操作かの照合 | 照合中。11/14に報告 |
| 外部サービス側の異常の見張りを強める | 進行中。11/14に報告。目安は2026年12月中 |
| 登録と利用枠の付与の監視を強める | 進行中。11/14に報告。目安は2026年12月中 |
| バックアップの保管の守りを強める | 進行中 |
| メールを送る全ドメインに DMARC を設定し、拒否する設定へ段階的に移す(主な7ドメインは監視の設定まで済み) | 進行中。目安は2026年12月中 |
| 人の管理画面の権限と、AI に持たせる権限を、仕組みとして分ける(上の道具の除外に続く見直し) | 進行中(AI から道具を外す部分は済) |
| コード実行の再開 | 鍵のない別マシンで動かす作りに改めるまで再開しない。再開するときは事前に告知 |
当社の作業ミス:11/9 16:49〜17:10、データベースの鍵の入れ替えで、道具の「成功」をそのまま信じ、無効な値を本番に入れて、サービスを21分止めました。新しい鍵で実際に接続できることを確かめてから入れる手順に改めました。
同じ日の 19:00〜19:31 ごろには、決済の鍵の整理で、まだ使われていた鍵まで無効にし、当社のアプリ25と Worker 5つで決済を止めました。19:03 に見張りが検知し、19:24 と 19:31 に新しい鍵で戻しました。この時間帯に完了した決済は0件で、二重の請求や、支払い後の反映漏れはありませんでした(無効な鍵での呼び出しは決済会社に届かないため、失敗した件数は数えられません)。鍵を無効にする前に、サーバーについては同じ鍵を使う所を設定から自動で洗い出し、サーバー以外の配布先は一覧で管理したうえで、すべてで新しい鍵が使えることを確かめてから無効にする手順に改めました(次回の入れ替えから使います。11/14 までに、本番を変えない形で試します)。
6. 報告と通報
- 個人情報保護委員会:11/9 に速報を提出しました。確報は 2027-01-07 までに出します。
- 詐欺メール:11/9 17:50 に、イタリアの CERT-AgID、ベルギーの Safeonweb(CCB)、pagoPA、Orange、メール送信の事業者に通報しました。
- 決済会社:契約に基づく連絡を、11/9 に行いました。
7. 守(Mamori)として
私たちは「守(Mamori)」というセキュリティの見張り役を作っています。それでも防げませんでした。Mamori が見ていたのは、端末やサーバーの設定と、世の中で知られている攻撃の情報です。アプリの作り、鍵の持ち方、外部サービスの異常は、見ていませんでした。
ここまで細かく公開するのは、同じ作りのサービスを持つ方に、同じことを起こしてほしくないからです。防御に役立つ痕跡(悪用された鍵を試した接続元など)は、公的な窓口(CERT・警察)と非公開で共有します。
濱田優貴(株式会社イネブラ 代表取締役)
Technical Report: From an AI "Code Execution" Tool to the Theft of Nearly All of Our Production Secrets
Enabler Inc. (operator of teai) / Published November 9, 2026 / All times are JST (UTC+9)
To Our Customers (Please Read First)
This report is written for engineers. What we ask of customers, and a detailed explanation of the information that may have been read, are in our notice. The key points are below.
Information that may have been read
- For everyone registered with teai (up to 2,536 people): names and email addresses, usage records, and passwords. (Passwords are not stored as-is. Of the 69 people who log in with a password, the passwords of the 47 people stored under our old scheme are easier to guess when combined with the leaked key. The remaining 22 people's passwords are now stored under a stronger scheme, but because we are still confirming when they were switched, we are treating them as equally easy to guess. We will also notify all 69 people individually.) For some people, conversations and AI memories; and the contents of inquiries sent to our support. We are treating the copy of our database as having been taken.
- Information we hold with our payment processor (Stripe): names, email addresses, billing and shipping addresses, phone numbers (only for people who entered one), card brand and last four digits, expiration dates, and payment history. This includes customers of our services other than teai. We do not store full card numbers.
- The recipients, subject lines, and bodies of emails sent from our services.
- Data we stored in the cloud (Cloudflare) was also read. We are checking whether it included customer information.
We are investigating how much was actually read.
What we ask you to do
- If you log in with an email address and password, open teai.io yourself and reset your password. If you use the same password anywhere else, change it there too.
- If you have ever registered another company's API key with teai, regenerate it with that provider. (As of our count on November 9, customers had registered 0 such keys.)
- If you use Sente, te, or the teai API, create a new API key at teai.io/keys and delete your old keys. On November 21, we will disable all keys that existed before 17:10 on November 9.
- Do not open links in emails that claim to be from us.
What we have confirmed so far
- API keys issued by teai are stored in an irreversible form. However, because the attacker could write to the database, we cannot rule out that fake keys were added. For that reason, as described in item 3 above, we will disable them all at once on November 21.
- Within the scope we have examined, we have found no tampering with our GitHub repositories or CI (some configuration changes are still being checked). The te installer matched the contents of the repository (verified by SHA-256). We are still verifying the Sente application itself.
- There have been no suspicious refunds of customer payments, and our receiving bank account has not been changed (the attacker's 23 payments were refunded by us).
- For safety, we have ended everyone's web login sessions. Please log in again.
Inquiries: teai.io/contact
Summary
- The AI in teai's chat had a tool that could run shell commands (code_execute). This tool ran as root on the same machine as the service itself. By asking the AI, a user could read the environment variables of the main service process. Those environment variables contained nearly all of our production secrets (about 100).
- Period: 2026-09-08 to 2026-11-09 (when we discovered it). About two months.
- With the secrets that were read, the following happened:
- The attacker gained direct read/write access to the database
- Our CEO's account was taken over
- Data was written to our backup storage (we are treating it as if data was also taken)
- About 76,000 phishing emails were sent from our domains
- Usage credits were granted without authorization
- Root causes
- An execution environment with no isolation
- Keeping all secrets in one place and sharing powerful keys
- Relying on the AI's judgment for defense, and not monitoring for anomalies on the side of external services
1. Architecture (at the Time)
- A single Rust (axum) binary ran on a group of Fly.io VMs, with data stored in Turso (libSQL). Backups were replicated to S3 with Litestream.
- Secrets were stored as Fly secrets and loaded into the environment variables of the main process. They included keys for the database, email sending, payments, AI providers, cloud services, the admin API, the master key for data encryption, and even the key used for password verification.
- The chat AI could use more than 50 tools, one of which was code_execute.
How code_execute was built (at the time)
- Where it ran: on the same VM as the main service. The user was the same root as the main service.
- Protections in place: clearing the child process's environment variables, a separate working directory per user, and a time limit.
- Protections missing
- Process namespace isolation
- Restricting
/proc(hidepid) - Running as a separate user
- A read-only file system
- Restricting outbound network traffic
- Result: the child process's environment variables were empty, but the main process's environment variables could be read from
/proc. The persistent volume (/data) was also readable and writable. - Output was streamed straight to the screen. Up to about 6,000 characters of tool output were passed to the AI, and the first 500 characters were also shown as-is on the user's screen. Even when the AI refused to summarize, the user still received the raw output.
- In practice, the only thing responsible for refusing dangerous requests was the AI's judgment. The attacker disguised the requests as legitimate work and encoded the output, getting past the AI's judgment.
2. How the Attack Unfolded (Confirmed Facts)
Accounts are identified by letters (A–F).
| Date/time (JST) | Who | What happened |
|---|---|---|
| 9/8– | A (4 accounts registered with emails at nonexistent domains) | Explored the inside of the server using code_execute |
| 9/21 | B | Obtained the main process's environment variables. Used the admin key to grant itself 200,000 credits. Placed a marker file in /data |
| 9/22 00:24 | (External) | Used the leaked cloud key to write a marker file into the backup storage (S3) |
| 9/22–11/7 | (About 10 external IPs) | Used the leaked cloud key to probe permissions across the board. Writing to one S3 bucket succeeded. Reading was also possible under the permissions, but because there are no logs, we treat the data as taken. Other operations were denied |
| 9/25 | — | The value of the AI usage (OpenRouter) key was obtained |
| 9/27 16:33 | C | Tried 5 passwords against our CEO's email address (all failed) |
| 9/27 16:41 | C | Used the leaked database key to write a forged login session for our CEO's account directly into the database (expiring 2027-12-31). Created an API key as our CEO's account and granted 500,000 credits |
| 9/27– | C (as our CEO) | Obtained the full contents of the environment variables, including the data encryption key, the password verification key, and the admin key. Data we stored in the cloud (Cloudflare KV) was also read (we are checking whether it included customer information) |
| 9/28 | — | An SSH server and a terminal-sharing tool (tmate) were started on the server. It is unknown whether anyone actually connected from outside. On the same day there was a configuration-only release (v1407) (we are checking whether this was our own operation) |
| 10/12–11/9 16:48 | (Directly from outside) | 75,964 phishing emails sent with six of our domains as the sender. The keys used were not necessarily only teai's keys (sending continued with other keys in the same email-sending account after teai's keys were deleted) |
| 11/3, 11/7 | D, E | Obtained the environment variables using the same technique |
| 11/9 | — | We discovered it from database records while investigating a problem with AI usage balances |
| 11/9 | F | After the accounts were isolated, re-registered twice using disposable addresses from the same family (13:32 and 15:20; neither was used; both isolated). On the same day, the attacker again attempted a purchase with the same card, apparently via a different checkout page (rejected by the payment processor's fraud detection) |
What the attacker wrote directly to the database: one forged login session and one working table (empty when discovered). (Creating API keys and granting credits were done through the app's own features.) Within the scope we have examined, we have found no sign that customer data was altered. We have not yet finished checking all records.
Money
- E made 23 purchases totaling ¥392,350 with a single Amex card. Because we suspect it is a stolen card, on 11/9 we refunded the full amount to the card and cancelled the attacker's subscription.
- D made purchases totaling ¥7,850 with two Visa cards authenticated with 3-D Secure.
- AI usage fees: of about $6,900 used since 10/29 (compared with the balance we recorded that day), we cannot account for about $4,925. It may have been used with the key leaked on 9/25, and we are investigating.
- There have been no suspicious refunds of customer payments, and our receiving bank account has not been changed (the attacker's 23 payments were refunded by us).
3. Why We Failed to Prevent It
- We drew the isolation boundary in the wrong place: we thought clearing the child process's environment variables was isolation. As long as it is the same machine and the same user, the main process is visible from
/proc. - We showed raw output to users: separately from the AI's judgment, tool output flowed straight to the screen.
- We counted the AI as a defense: AI can be fooled. Defenses should have been placed in permissions, the network, and the file system.
- We kept all secrets in one place and shared powerful keys
- All secrets sat in plaintext in the main process's environment variables.
- A full-permission email-sending key was shared across multiple services, and the payment key was shared across 25 of our apps and 5 Workers (our distribution list covered only 14 of those apps).
- Admin privileges were also available in chat: in a regular user's chat, only the first 500 characters of tool output appear on screen. We believe the attacker took over our CEO's account because, in our CEO's chat, admin-only tools were also available and the full contents of the environment variables could be received. We had not separated the permissions of the human admin console from the permissions given to the AI.
- Login sessions were stored in plaintext: anyone with the database key could write an arbitrary login session. This was the direct cause of the account takeover.
- Old passwords were left in place: in August we switched to a slow hash (argon2), but migration happened only "at the next login." Of the 69 people with passwords, the passwords of the 47 who had not logged in remained in a fast hash with a secret key added (the old scheme), and that key leaked.
- We did not notice abuse of sign-up and credit grants: accounts could be registered with nonexistent domains or disposable addresses. There were no alerts for grants of 200,000 or 500,000 credits.
- We were not watching the outside: there was no monitoring for the following anomalies, and we did not notice for about a month.
- Phishing email sending volume and complaint rate
- AI usage fees
- Spikes in cloud permission errors
- Outbound network traffic (tmate is a tool that connects outward)
4. What We Ask You to Check in Your Own Environment
For those building services that give tools to an AI. Please check these in a test environment (do not try them in production).
- When you run
idinside the AI's tool, are you root? - From inside the tool, can you see processes other than your own? (If
psshows the main service process, isolation is insufficient.) - From inside the tool, can you communicate with the outside?
- Is even one production secret present in the tool's execution environment?
- Are you returning tool output to users without inspecting it (detection of secret-like strings)?
- Are login sessions and API keys stored as hashes?
- When you changed your password storage scheme, did you force migration for people still on the old scheme?
- Is your database key a single read/write key (have you separated it from a read-only key)?
- When rotating keys, do you confirm that you can actually connect with the new key, and that nothing is still using the old key, before disabling the old key? (We took our own services down by missing these two points.)
- Are your keys for external services separated per service and per purpose, with only the permissions they need?
- Are you monitoring for anomalies on the side of external services (sending volume, complaint rate, usage fees, permission errors)?
Isolation options include microVMs (such as Firecracker), gVisor, and at a minimum process namespace isolation with hidepid=2, plus running as a separate user.
5. Response and Prevention
| Measure | Status |
|---|---|
| Disable by default code_execute and other tools that run commands or perform file operations on the server | Implemented and deployed to production (11/9) |
| Automatically remove secrets from tool output (the values themselves, hex, base64, and key-like patterns) | Implemented and deployed to production (11/9) |
| Remove tools that return server state or configuration from the AI | Implemented and deployed to production (11/9) |
| Isolate the 13 involved accounts and revoke their API keys and logins (A–F in the table, plus accounts we judged to be from the same family based on registration source and usage patterns) | Done (11/9) |
| Delete the forged login session for our CEO's account and the keys created by the attacker | Done (11/9) |
| Rotate the database key (all old keys disabled) | Done (11/9 17:10) |
| Rotate the data encryption key and re-encrypt | Done (11/9) |
| Rotate the admin key and AWS keys | Done (11/9) |
| Email-sending keys: delete all and move to send-only keys per app | Done (11/9 17:36). Confirmed no further phishing emails at 17:37 on 11/9 and again after 22:00 (the most recent sends in the sending log) |
| Store login sessions as hashes and end all web login sessions | Implemented and deployed to production. Sessions also ended, with 0 remaining confirmed (11/9) |
| Payment keys | Done (11/9; confirmed that the new keys work across all services) |
| Keys for Cloudflare, RunPod, Google, LINE, and AI providers | Partly done (on 11/9 we replaced the Cloudflare global key and the OpenRouter and Google AI keys, and deleted the old keys). The rest are in progress |
| Rebuild production machines, or confirm no planted mechanisms remain | Being checked |
| Ask the 47 people on the old scheme to reset their passwords and block login with the old scheme (also ask all 69 people with passwords, as a precaution; resetting moves them to argon2) | Reset mechanism deployed to production. Blocking login with the old scheme: Done (deployed on 11/9; confirmed 403 in production). Individual notices: to be sent |
| Leaked GitHub token | Already invalid as of 11/9 (when it became invalid is still being checked). Within the scope we have examined, no sign of misuse during the attack period |
| Investigate the unaccounted-for AI usage fees (about $4,925) | Under investigation. Will report on 11/14 |
| Reissue 10 integration tokens for our CEO's account | In progress |
| Check whether the configuration-only release on 9/28 (v1407) was our own operation | Being checked. Will report on 11/14 |
| Strengthen monitoring for anomalies on the side of external services | In progress. Will report on 11/14. Target: within December 2026 |
| Strengthen monitoring of sign-ups and credit grants | In progress. Will report on 11/14. Target: within December 2026 |
| Strengthen protection of backup storage | In progress |
| Set up DMARC on all domains that send email and move in stages to a reject policy (monitoring configured for the 7 main domains) | In progress. Target: within December 2026 |
| Structurally separate the permissions of the human admin console from the permissions given to the AI (a review following the tool removal above) | In progress (removing the tools from the AI is done) |
| Resuming code execution | Will not resume until it is redesigned to run on a separate machine with no secrets. We will announce in advance before resuming |
Our own operational mistakes: from 11/9 16:49 to 17:10, while rotating the database key, we trusted a tool's "success" message at face value, put an invalid value into production, and took the service down for 21 minutes. We changed our procedure to confirm that we can actually connect with the new key before putting it in place.
On the same day, from about 19:00 to 19:31, while cleaning up payment keys, we also disabled a key that was still in use, which stopped payments on 25 of our apps and 5 Workers. Our monitoring detected this at 19:03, and we restored service with new keys at 19:24 and 19:31. Zero payments were completed during this window, and there were no double charges or payments that failed to be applied after being made. (Calls made with an invalid key do not reach the payment processor, so we cannot count how many failed.) We changed our procedure so that, before disabling a key, we now automatically find every server that uses it from our configuration, track non-server destinations in a list, and disable the old key only after confirming the new key works everywhere (this applies from the next rotation; we will test it without touching production by 11/14).
6. Reporting and Notifications
- Personal Information Protection Commission (Japan): we submitted a preliminary report on 11/9. We will submit the final report by 2027-01-07.
- Phishing emails: at 17:50 on 11/9, we reported them to CERT-AgID (Italy), Safeonweb (CCB, Belgium), pagoPA, Orange, and our email-sending provider.
- Payment processor: we made the notification required under our contract on 11/9.
7. As the Makers of Mamori
We build a security watchdog called "Mamori" (守). Even so, we could not prevent this. What Mamori watched was the configuration of devices and servers, and publicly known attack information. It did not watch how applications are built, how secrets are held, or anomalies in external services.
We are publishing this level of detail because we do not want the same thing to happen to others running services built the same way. Traces useful for defense (such as the source addresses that tried the misused keys) will be shared privately with public authorities (CERTs and the police).
Yuki Hamada (CEO, Enabler Inc.)
Related: Notice (what to do) / Technical report / Phishing emails / Contact: teai.io/contact
関連:お知らせ(お願い) / 代表のまとめ / 技術レポート / 停止のお詫び / 対応の記録 / 詐欺メールについて/お問い合わせ:teai.io/contact