🚨 DỪNG LẠI. Làm 3 việc này NGAY BÂY GIỜ:

  1. Revoke token. npm: npm token revoke <token-id> / GitHub: github.com/settings/tokens > Delete / AWS: aws iam deactivate-access-key --access-key-id <key>
  2. Coi như mọi thứ token truy cập được đã bị compromise.
  3. CHƯA xóa log, force-push, hay post công khai.

Xong rồi? Đọc tiếp.

TL;DR — Attacker thu thập credential bị lộ từ public repo trong 5 phút. Bạn có 1 giờ trước khi thiệt hại tăng lên. Runbook này hướng dẫn revocation, scoping blast radius, rotate downstream, forensics, và hardening, với command chính xác cho npm, GitHub, Vercel, và AWS. Nhảy đến Phút 0-5 →

📊 Khoảng cách chết người:

  • Bot scan GitHub tìm key bị lộ trong 5 phút
  • Team trung bình mất 94 ngày để phát hiện secret bị lộ
  • Breach liên quan credential mất 292 ngày để xử lý
  • 53% tổng số data breach liên quan đến credential bị đánh cắp

Bạn vừa nhận notification từ GitHub rằng npm token bị tìm thấy trong public commit. Hoặc chạy git log thấy AWS key nằm plaintext. Hoặc GitHub Secret Scanning vừa gửi email.

Nhịp tim tăng. Bình thường.

Những gì bạn làm trong 60 phút tới quyết định đây là phiền phức 1 giờ hay sự cố 1 tuần. Tôi đã trải qua chuyện này hai lần. Lần đầu tôi hoảng và force-push. Tệ hơn. Lần hai tôi theo runbook này. Xử lý trong 45 phút.

Đây là runbook.


Phút 0-5: Revoke token

Revoke token bị lộ ngay lập tức. Chưa cần scope damage. Chưa cần điều tra nguyên nhân. Chưa cần clean git history. Revoke. Mỗi phút token còn sống, scanner tự động có thể dùng nó. Threat actor thu thập credential từ public repo trong 5 phút (DevActivity/GitHub, 2026).

Một command mỗi platform:

npm

Terminal window
# Liệt kê token để tìm cái bị lộ
npm token list
# Revoke
npm token revoke <token-id>

GitHub PAT

Terminal window
# Qua CLI (nếu có gh)
gh auth token # xem token hiện tại
# Rồi vào github.com/settings/tokens > Delete token bị lộ
# Hoặc qua API (fine-grained token)
gh api -X DELETE /user/tokens/<token-id>

GitHub OAuth và App credential dùng Credential Revocation API (GA từ tháng 3/2026).

AWS

Terminal window
# Deactivate trước, rồi delete
aws iam deactivate-access-key --access-key-id AKIA...
aws iam delete-access-key --access-key-id AKIA...

Vercel

Project Settings > Environment Variables > click biến > Regenerate. Hoặc qua CLI:

Terminal window
vercel env rm <VAR_NAME> production
vercel env add <VAR_NAME> production

GCP

Terminal window
gcloud iam service-accounts keys delete <key-id> \
--iam-account=<service-account-email>

Nếu bạn đọc bài này lúc 2 giờ sáng vì GitHub vừa gửi email, bắt đầu từ đây. Copy command. Chạy. Rồi thở.

Key insight: Threat actor thu thập IAM credential từ public repo trong 5 phút, trong khi team trung bình mất 94 ngày để phát hiện secret bị lộ (Verizon DBIR, 2025). Khoảng cách giữa 5 phút và 94 ngày là nơi breach xảy ra. Revoke ở Phút 0 đóng khoảng cách đó.


Phút 5-15: Scope blast radius

Token đã bị revoke. Giờ xác định nó có thể truy cập gì. Blast radius phụ thuộc ba thứ: loại token, scope/permission, và thời gian bị lộ. Classic GitHub PAT có scope repo và không hết hạn là worst-case: full read/write mọi repo, kể cả private.

Loại tokenBlast radiusWorst-case access
npm publish tokenPackage của bạnAttacker publish version độc
npm read-only tokenPackage metadataRủi ro thấp, vẫn nên rotate
GitHub classic PAT (repo)Mọi repo, kể cả privateSource code, secret trong code, CI config
GitHub fine-grained PATRepo được chọnGiới hạn trong repo đã chọn
AWS IAM access keyPhụ thuộc IAM policyCó thể là toàn bộ AWS account
Vercel env varSecret một projectAPI key, DB credential, OAuth token

Cách kiểm tra access

GitHub: Check security log trong exposure window:

Terminal window
# Tài khoản cá nhân
# Settings > Security log > filter theo date range
# Org account (nếu có admin)
gh api "/orgs/{org}/audit-log?phrase=action:oauth_authorization.create"

AWS CloudTrail: Query access event cho key bị lộ:

Terminal window
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIA... \
--start-time 2026-04-28T00:00:00Z \
--end-time 2026-04-30T23:59:59Z

Exposure window: Token bị commit khi nào? (git log --all --oneline | head -20 để tìm commit). Revoke khi nào? Khoảng cách đó là compromise window. Mọi thứ bị truy cập trong window đó đều có thể bị compromise.

Key insight: Stolen credential chiếm 22% tổng số security incident và mất trung bình 292 ngày để xử lý, là loại breach tốn thời gian nhất (IBM/Deepstrike, 2025). Scope blast radius ở Phút 5-15 ngăn cái đuôi 292 ngày.


Phút 15-30: Rotate mọi thứ downstream

Token bị lộ đã chết. Nhưng nếu nó truy cập được secret khác, những secret đó cũng bị compromise. Đây là cascade biến sự cố 1 giờ thành sự cố 1 tuần. Rotate mọi credential mà token bị lộ có thể chạm tới.

Checklist cascade

CI/CD secret (kiểm tra trước):

Terminal window
# GitHub Actions secrets - regenerate qua web UI
# Settings > Secrets and variables > Actions > Update từng secret
# Vercel env vars
vercel env ls production
# Regenerate bất cứ cái gì token bị lộ có thể đọc

npm publish token: Nếu credential bị lộ đọc được CI environment (ví dụ GitHub PAT có repo access đến project lưu npm token trong GitHub Actions secrets), publish token đã bị compromise.

Terminal window
npm token revoke <publish-token-id>
npm token create --cidr=<your-ci-ip-range>

Database credential: Nếu env var chứa DB connection string, rotate ở cấp database. Không chỉ update env var.

OAuth token: Nếu token bị lộ truy cập được Vercel env var chứa Google hoặc Slack OAuth token, coi như compromised. Chạy OAuth permissions audit từ bài Level 3.

SSH key: Nếu environment bị compromise có ~/.ssh/ accessible:

Terminal window
# Tạo key mới
ssh-keygen -t ed25519 -C "your_email@example.com"
# Thêm vào GitHub
gh ssh-key add ~/.ssh/id_ed25519.pub --title "rotated-$(date +%Y%m%d)"

Dev solo: tối đa 5-10 secret. Team lead: nhân với số service CI pipeline chạm tới. Mở shared doc và check off từng cái.

Key insight: 53% tổng số data breach liên quan stolen credential, chi phí trung bình $4.44 triệu mỗi vụ (IBM Cost of a Data Breach / Deepstrike, 2025). Cascade từ một token bị lộ đến downstream credential là thứ đẩy chi phí lên. Cắt cascade ở Phút 15 là action có ROI cao nhất trong runbook.


Phút 30-45: Export log trước khi hết hạn

Export audit log NGAY, trước khi platform xóa. GitHub giữ security event 90 ngày. AWS CloudTrail giữ 90 ngày mặc định. npm audit log hạn chế. Nếu không export bây giờ, bạn mất bằng chứng forensic cần cho post-mortem.

Checklist export log

PlatformExport gìCáchRetention
GitHubSecurity logSettings > Security log > Export90 ngày
AWSCloudTrail eventaws cloudtrail lookup-events (xem trên)90 ngày
VercelDeployment logDashboard > Deployments > filter theo ngày30 ngày
npmToken last-usednpmjs.com/settings/~/tokensHạn chế

Tìm gì trong log:

  • Access từ IP hoặc location lạ
  • Token mới được tạo trong exposure window
  • Package được publish (cho npm token)
  • Repo clone hoặc API access ngoài pattern bình thường
  • SSH key mới được thêm vào account

Nhận tip bảo mật hàng tuần cho AI coder. Hooks, credential hygiene, và phân tích breach thực tế. Một email mỗi tuần. Đăng ký AI Developer Weekly →

Key insight: Team trung bình mất 94 ngày để phát hiện secret bị lộ (Verizon DBIR, 2025). Export log ở Phút 30-45 đảm bảo bạn có bằng chứng forensic ngay cả khi exposure xảy ra từ tuần trước. Platform xóa log theo lịch của họ, không phải của bạn.


Phút 45-60: Hardening cho lần sau

Lửa đã tắt. Giờ ngăn lần tiếp theo. Ba thay đổi mất 15 phút loại bỏ vector credential leak phổ biến nhất. Riêng GitHub Push Protection đã chặn 39 loại token trước khi vào repo (GitHub Docs, 2026), và fine-grained token với expiration 90 ngày đóng cửa sổ classic PAT đã gây ra vụ axios breach.

1. Bật GitHub Push Protection (miễn phí cho public repo):

Terminal window
# Kiểm tra secret scanning đã bật chưa
gh api /repos/{owner}/{repo} --jq '.security_and_analysis'

Push Protection chặn 39 loại token trước khi vào repo. Không bắt custom secret, nhưng bắt npm, AWS, GCP, Stripe, và hầu hết provider lớn (GitHub Docs, 2026).

2. Chuyển sang fine-grained GitHub token với expiration 90 ngày. Classic PAT không hết hạn mặc định. Fine-grained token expire, scope cho repo cụ thể, và hỗ trợ IP restriction.

3. Xây defense nhiều lớp với supply chain series:

LevelDefenseBài viết
1.npmrc hardeningnpm Defense 30 Giây
2PreToolUse hooksChặn npm Attack với Hooks
3OAuth audit + scope hygieneOAuth Supply Chain Defense
4Incident response (bài này)Bạn đang đây

5 hành động hoảng loạn khiến token leak tệ hơn

Điều tệ nhất sau credential leak là hoảng loạn và làm tệ hơn. Breach liên quan credential đã mất trung bình 292 ngày để xử lý (IBM/Deepstrike, 2025). 5 anti-pattern sau đây thêm hàng tuần lên trên đó bằng cách phá hủy bằng chứng, báo động attacker, hoặc delay thông báo team.

Anti-patternTại sao tệ hơnLàm gì thay thế
Force-push để xóa commitToken đã trong GitHub event log và bot cache. Force-push phá audit trail.Revoke token trước. Clean history sau bằng git filter-repo.
Xóa repoCommit đã bị bot scrape. Giờ mất code VÀ log.Revoke, export log, rồi clean history.
Rotate credential trước khi export logMất audit trail cho biết gì đã bị truy cập trong exposure window.Export log trước, rotate sau (trừ khi token còn live thì revoke ngay).
Chờ mới thông báo teamMỗi giờ delay là mỗi giờ team không bảo vệ được downstream system.Thông báo trong 15 phút sau khi xác nhận leak.
Post công khai trước khi revokeCông bố leak là tín hiệu cho attacker move nhanh hơn.Revoke trước. Disclose sau khi containment xong.

Key insight: Force-push để xóa committed secret phá git reflog audit trail và không xóa secret khỏi GitHub event log, cached fork, hay database bot đã scrape. Revocation luôn phải trước history cleanup (GitHub Docs).


Kế hoạch 7 ngày sau incident

Runbook 60 phút cầm máu. Kế hoạch 7 ngày ngừa nhiễm trùng. Với 2 tỷ credential bị lộ được tổng hợp từ dark web chỉ trong 2025 (Deepstrike, 2025), câu hỏi không phải bạn có gặp incident nữa không, mà là bạn có chuẩn bị sẵn không.

  • Ngày 1-2: Monitor audit log tìm access trong exposure window bạn bỏ sót. Đặt alert cho hoạt động bất thường trên account bị ảnh hưởng.
  • Ngày 3: Document incident. Gì bị lộ, exposure window, gì đã rotate, gì đã bị truy cập. Giữ doc này cho reference sau.
  • Ngày 4-5: Review secrets management. Đã dùng env var thay hardcoded key chưa? .env có trong .gitignore chưa? CI secret scope minimum necessary chưa?
  • Ngày 6-7: Mini-retro với team (hoặc với chính mình). Không blame. Process nào fail? Automation nào sẽ bắt được? PreToolUse hook có chặn được commit không?

Khi nào nên gọi chuyên gia?

Nếu credential bị lộ có quyền truy cập customer data, hệ thống tài chính, hoặc production database chứa PII, dừng guide này và liên hệ incident response firm chuyên nghiệp. Yêu cầu pháp lý thay đổi hoàn toàn playbook.

Ngưỡng escalation:

  • Customer data có thể bị truy cập: nghĩa vụ pháp lý phải disclose ở nhiều quốc gia (GDPR: 72 giờ)
  • Production database credential bị lộ: assume data exfiltration cho đến khi chứng minh ngược lại
  • Nhiều token bị lộ cùng lúc: có thể là system compromise rộng hơn, không chỉ một credential leak

Thử ngay:

  1. Chạy npm token list và check token nào không có expiration hoặc scope quá rộng
  2. Vào github.com/settings/tokens và thay classic PAT bằng fine-grained token (expiry 90 ngày, scope repo cụ thể)
  3. Bật Push Protection: Settings > Code security > Secret scanning > Push protection
  4. Bookmark trang này. Bạn sẽ cần nó lúc 2 giờ sáng khi notification đến.

Muốn ngăn credential leak tiếp theo? Bắt đầu với .npmrc defense 30 giây, rồi build up. Tham gia AI Developer Weekly → cho tip bảo mật hàng tuần.


FAQ

Bot scan GitHub tìm key bị lộ nhanh cỡ nào?

Trong vòng 5 phút. Scanner tự động liên tục monitor public commit trên GitHub. Researcher đã document credential harvesting trong vài phút sau exposure. Khi bạn phát hiện leak, token có thể đã bị copy. Đây là lý do Phút 0 là revocation, không phải investigation.

Có nên xóa commit chứa key bị lộ không?

Chưa vội. Revoke token trước. Export log thứ hai. Rồi clean git history bằng git filter-repo hoặc BFG Repo-Cleaner. Force-push trước khi revoke phá audit trail mà không xóa exposure, vì commit data đã trong GitHub event log và có thể đã bị cache bởi third-party service.

GitHub Secret Scanning có bắt được tất cả token không?

Không. GitHub hỗ trợ 39 loại token với push protection mặc định, bao gồm AWS, npm, Stripe, và Google Cloud. Nhưng custom API key, database password, self-hosted service token, và internal secret không được detect. Secret scanning là lưới an toàn, không phải bảo đảm. Kết hợp với .gitignore discipline và pre-commit hook.

Rotate token bị lộ là đủ, hay phải rotate hết?

Rotate tất cả những gì token bị lộ có thể truy cập. Nếu npm token đọc được CI secret, secret đó cũng bị compromise. Nếu GitHub PAT có scope repo, mọi secret trong repo đó bị lộ. Nếu Vercel env var chứa database credential, rotate ở cấp database. Theo cascade mô tả trong phần Phút 15-30.


Đọc tiếp