Hướng dẫn bảo vệ MCP server và API key Claude khi lập trình với AI
Vì sao MCP server ghim phiên bản vẫn có thể đổi thư viện mỗi lần chạy, API key bị lợi dụng ra sao, và cách đóng băng MCP server, bảo vệ khoá từng bước.

Trong bài này
- 17 phút đọc
- 11 phần
- 5 mẫu sao chép được
- 1 bảng tra cứu
Mục lục
- Bối cảnh: điều đã được công bố
- MCP server nằm ở đâu trong trợ lý lập trình
- Ghim phiên bản không ghim phụ thuộc
- Cách đóng băng một MCP server
- API key Claude bị biến thành kênh điều khiển
- Bảo vệ API key khi vibe code
- MCP dễ dựng, khó cấp quyền
- Hiểu lầm phổ biến
- Bảy việc nên làm tuần này
- Câu hỏi thường gặp
- Kết luận
Cách bài viết này được thực hiện: bài dựa trên nghiên cứu của Corelight (blog ngày 10/11/2026), báo cáo của Darktrace (ngày 12/11/2026), tài liệu kiến trúc chính thức của Model Context Protocol và bài phân tích “MCP is dead simple” của lập trình viên Sylwia Laskowska (12/11/2026), kiểm tra ngày 14/11/2026. Các đoạn lệnh và mã là ví dụ minh hoạ, cần chỉnh theo dự án; không có khoá hay token thật nào trong bài.
Bạn cài một MCP server cho Claude Code hay Cursor bằng đúng một dòng cấu hình, ghi rõ số phiên bản, và yên tâm rằng nó sẽ chạy y như hôm cài. Nghiên cứu mới của Corelight cho thấy điều đó chưa chắc đúng: một server ghim cố định đã chạy với 15 bộ thư viện phụ thuộc khác nhau chỉ trong năm tuần.
Cùng tuần, Darktrace công bố thử nghiệm cho thấy một API key Claude bị lấy cắp có thể biến Claude Code thành “tay trong” nhận lệnh từ xa, và mọi kết nối đều đi tới máy chủ của Anthropic nên rất khó phát hiện. Hai nghiên cứu khác nhau nhưng chung một bài học cho người vibe code: thứ bạn cắm vào trợ lý lập trình AI cần được quản như mã chạy trên production.
Câu trả lời ngắn: Ghi số phiên bản trong lệnh uvx hay npx không khoá được các thư viện phụ thuộc của MCP server; muốn chắc chắn, hãy ghim theo commit, cài từ file lock có hash và chạy trực tiếp file đã cài. Với API key Claude, ưu tiên đăng nhập OAuth, dùng khoá ngắn hạn quyền hẹp, không để khoá trong file cấu hình shell, và đổi khoá ngay khi nghi lộ.
Tóm tắt nhanh
- Corelight: 23 trên 35 MCP server được khảo sát có cách cài khuyến nghị tải phụ thuộc mới từ kho công khai mỗi lần chạy, cài hoặc dựng image.
- Một server ghim theo commit vẫn đổi 23 trên 69 gói phụ thuộc, gồm cả thư viện mã hoá và MCP SDK.
- Darktrace: với API key Claude lấy được từ máy lập trình viên, kẻ tấn công dùng memory store làm kênh ra lệnh và Files API để rút 1 GB dữ liệu trong phòng lab.
- Darktrace nói rõ đây không phải lỗ hổng của nền tảng Claude và chưa thấy kỹ thuật này dùng ngoài thực tế.
- MCP chỉ chuẩn hoá cách gọi công cụ; phân quyền, phê duyệt và chống làm trùng vẫn là việc của bạn.
Nội dung chính:
- Chuyện gì vừa được công bố
- MCP server nằm ở đâu trong trợ lý lập trình
- Ghim phiên bản không ghim phụ thuộc
- Cách đóng băng một MCP server
- API key Claude bị biến thành kênh điều khiển
- Bảo vệ API key khi vibe code
- MCP dễ dựng, khó cấp quyền
- Hiểu lầm phổ biến
- Bảy việc nên làm tuần này
- Câu hỏi thường gặp
Bối cảnh: điều đã được công bố
Ngày 10/11/2026, James Lagermann, giám đốc liên minh kỹ thuật của hãng bảo mật mạng Corelight, đăng nghiên cứu về rủi ro chuỗi cung ứng trong MCP server. Ông theo dõi một MCP server cộng đồng được cấu hình đúng một bản phát hành và một commit. Trong năm tuần, trình khởi chạy dựng lại môi trường 19 lần, tạo ra 15 môi trường khác nhau; 23 trên 69 gói phụ thuộc đã đổi phiên bản, trong đó có thư viện cryptography, PyJWT (bốn phiên bản) và MCP SDK.
Hai ngày sau, Darktrace công bố báo cáo “Living off the AI” của nhà nghiên cứu Moishe Tajtelbaum. Nhóm này dựng một mạng doanh nghiệp giả lập, dùng API key Claude lấy từ máy bị chiếm, rồi điều khiển Claude Code qua memory store (kho “trí nhớ” dạng file văn bản gắn với workspace trên Claude Console). Agent chạy 9 lệnh, dò mạng, dò mật khẩu và rút ra một file 1 GB.

Cả hai đều không phải lỗ hổng phần mềm theo nghĩa thông thường. Không có bản vá nào bạn chỉ cần bấm cập nhật. Vấn đề nằm ở cách người dùng cài đặt và giữ khoá, tức là phần bạn kiểm soát được.
MCP server nằm ở đâu trong trợ lý lập trình
Model Context Protocol (MCP) là chuẩn mở để trợ lý AI gọi công cụ bên ngoài. Theo tài liệu chính thức, ứng dụng AI như Claude Code, Claude Desktop hay VS Code đóng vai MCP host. Với mỗi MCP server bạn cài, host tạo một MCP client giữ một kết nối riêng tới server đó.

Server chạy trên máy bạn thường dùng kênh stdio: ứng dụng AI khởi động server như một chương trình con. Server từ xa dùng Streamable HTTP và nên xác thực bằng OAuth. Điều quan trọng với bảo mật: server cục bộ chạy với quyền của chính bạn, đọc được file và biến môi trường bạn đọc được. Nếu mã của server đổi, quyền đó đi theo mã mới.
Ghim phiên bản không ghim phụ thuộc
Nhiều hướng dẫn cài MCP server cho trợ lý AI chỉ cần một dòng, kiểu như sau (ví dụ trích từ nghiên cứu của Corelight, phần trong ngoặc nhọn là chỗ bạn thay tên thật):
# Ghim theo tag Git
uvx --from git+https://github.com/<owner>/<server>@<release-tag> <server>
# Ghim theo phiên bản trên PyPI
uvx --from <package>==<version> <package>
# Proxy MCP từ xa chạy bằng npx với tag latest
npx <proxy>@latest <url>
Giải thích: uvx là lệnh của công cụ uv, tải một gói Python và chạy ngay trong môi trường tạm. npx làm việc tương tự với gói npm. Hai dòng đầu trông như đã khoá chặt vì có tag hoặc số phiên bản. Nhưng Corelight phát hiện trình khởi chạy dùng danh sách phụ thuộc khai báo của gói và bỏ qua file lock có hash mà dự án đã chuẩn bị. Khoảng 60 gói bên dưới được lấy mới từ PyPI mỗi khi môi trường bị dựng lại. Dòng thứ ba còn tệ hơn: @latest nghĩa là lần nào cũng có thể nhận mã mới.

Corelight ghi nhận trợ lý AI khởi động server đó 162 lần trong một tuần; phần lớn chỉ kiểm tra tag Git rồi dùng bộ nhớ đệm, nhưng bộ nhớ đệm chứa tới 19 bản dựng của cùng một bản phát hành. Câu tóm gọn của Lagermann: ghim phiên bản một gói không nhất thiết ghim các gói nó phụ thuộc.
Vì sao điều này nguy hiểm? Tháng 6/2026, một biến thể sâu Shai-Hulud trên PyPI đã nhắm vào các gói có chủ đề MCP và tìm khoá của trợ lý lập trình AI. Nếu một thư viện phụ thuộc bị chiếm, server “ghim cố định” của bạn vẫn có thể kéo nó về ở lần dựng lại kế tiếp. Trong khảo sát của Corelight, 23 trên 35 server có cách cài khuyến nghị kéo phụ thuộc từ kho công khai, và mọi quản trị viên Lagermann trao đổi đều dùng ít nhất một server như vậy. Đây cũng là lý do mmo.vn từng khuyên khoá GitHub Actions bằng lockfile: cùng một vấn đề, khác chỗ.
Cách đóng băng một MCP server
Corelight thử “đóng băng” năm server: ghim theo commit, cài một lần từ file lock có hash, chạy trực tiếp và tắt kiểm tra cập nhật. Trong hai tuần, năm server khởi động 457 lần và danh sách gói của mỗi server khớp hoàn toàn với ngày cài. Thời gian khởi động còn khoảng 2 giây, thay vì 4 đến 11 giây khi chạy qua trình khởi chạy.


Dưới đây là một cách làm cụ thể cho server Python có dùng uv và có file uv.lock, trên macOS hoặc Linux. Thay phần trong ngoặc nhọn bằng thông tin thật của server bạn dùng:
# 1. Lấy mã nguồn và ghim đúng một commit (không dùng tag)
git clone https://github.com/<owner>/<server>.git
cd <server>
git checkout <commit-sha>
# 2. Xuất danh sách phụ thuộc kèm hash từ file uv.lock của dự án
uv export --frozen --no-dev --format requirements.txt -o requirements.lock.txt
# 3. Cài vào môi trường riêng, bắt buộc kiểm hash
python3 -m venv .venv-mcp
.venv-mcp/bin/pip install --require-hashes -r requirements.lock.txt
# 4. Cài chính server mà không giải lại phụ thuộc
.venv-mcp/bin/pip install --no-deps .
Giải thích: --frozen bảo uv dùng nguyên file lock, không cập nhật. Lệnh uv export mặc định ghi kèm hash cho từng gói, nên ở bước 3, --require-hashes khiến pip từ chối bất kỳ gói nào có nội dung khác với hash đã ghi. Bước 4 dùng --no-deps để pip không tự kéo thêm gì. Nếu dự án không có uv.lock, bạn cần dùng file lock mà dự án cung cấp, hoặc tự tạo một lần rồi giữ nguyên.
Sau đó, trỏ cấu hình MCP của dự án (file .mcp.json mà Claude Code đọc) vào file chạy đã cài, thay vì gọi uvx:
{
"mcpServers": {
"<ten-server>": {
"command": "/duong-dan-tuyet-doi/<server>/.venv-mcp/bin/<server>",
"args": []
}
}
}
Giải thích: command là chương trình mà Claude Code khởi động khi cần server; dùng đường dẫn tuyệt đối tới file trong .venv-mcp để chắc chắn không đi qua trình khởi chạy tải mã. Corelight cũng khuyên tắt kiểm tra cập nhật lúc khởi động (framework MCP trong thử nghiệm của họ tự gọi PyPI để xem có bản mới) và kiểm tra lại: server vẫn bắt tay MCP bình thường, vẫn có đủ công cụ, danh sách gói sau nhiều lần khởi động vẫn khớp ngày cài.
Đóng băng không có nghĩa là bỏ mặc. Corelight chỉ ra một server cộng đồng sau khi đóng băng có 40 gói cũ hơn bản mà trình khởi chạy sẽ kéo về hôm đó, trong đó có gói nhạy cảm về bảo mật. Lagermann tự xem xét lỗ hổng cho các server của mình mỗi đêm và cập nhật sáng hôm sau kèm nhật ký thay đổi. Với cá nhân, một lịch xem lại hằng tuần hoặc hằng tháng là hợp lý.
API key Claude bị biến thành kênh điều khiển
Thử nghiệm của Darktrace bắt đầu từ giả định máy của một lập trình viên đã bị chiếm, và khoá Claude được để sẵn trên máy. Kẻ tấn công gửi khoá về máy chủ của mình, rồi dùng Claude API tạo một memory store. Darktrace lưu ý có thể tạo memory store qua API ngay cả khi tổ chức không dùng Claude Managed Agents.
Memory store gồm ba file: file heartbeat để mỗi tiến trình Claude Code báo “tôi còn sống”, file input chứa việc cần làm, file output chứa kết quả. Mỗi tiến trình Claude Code mới đọc việc, chạy, ghi kết quả; người điều khiển đọc kết quả và viết việc tiếp theo bằng tiếng Anh thông thường. Để giữ chỗ đứng, một đoạn shell tạo dịch vụ systemd liên tục khởi động Claude Code ở chế độ không cần xác nhận khi dùng công cụ.
Trong phòng lab, agent dò mạng nội bộ, tìm thấy máy chủ mở FTP, SMB và SSH, lấy danh sách tên nhân viên và một mật khẩu từ thư mục FTP cho phép truy cập ẩn danh, tạo danh sách 190 tên đăng nhập để thử mật khẩu vào máy điều khiển miền, tìm ra tài khoản khớp, liệt kê thư mục chia sẻ và tải về một file. File 1 GB được chia ba phần rồi đẩy lên qua Files API. Toàn bộ lưu lượng đi tới api.anthropic.com, đúng địa chỉ mà agent vẫn dùng hằng ngày.

Darktrace nhấn mạnh kỹ thuật này không dựa vào lỗ hổng nào của nền tảng Claude, chưa thấy dùng ngoài thực tế, và họ đã chia sẻ kết quả với Anthropic trước khi công bố. Theo Tim Bazalgette, giám đốc AI của Darktrace, nhóm mới thử trên một nền tảng; mức độ rủi ro phụ thuộc vào việc API của nhà cung cấp có kết hợp chỗ lưu văn bản với suy luận hay không, và endpoint tải file dùng để rút dữ liệu cũng có bản tương đương ở OpenAI.
Bảo vệ API key khi vibe code
Điểm mấu chốt trong thử nghiệm của Darktrace: khoá API thường tạo được memory store, còn thông tin đăng nhập OAuth thì không. Từ đó có mấy việc cụ thể bạn làm được ngay.

- Đăng nhập Claude Code bằng tài khoản thay vì dán API key nếu bạn dùng gói Pro, Max. Khi cần khoá API cho script, tạo khoá riêng cho từng dự án, đặt hạn mức chi tiêu và xoá khi xong.
- Không ghi khoá vào file cấu hình shell như
.bashrc,.zshrc, hay gõ thẳng trong lệnh (sẽ nằm trong lịch sử shell). Darktrace khuyên giữ khoá ngoài dotfile và biến môi trường cố định. - Coi khoá AI nghiêm như khoá production: kẻ có khoá không chỉ đốt tiền của bạn, mà còn có thể dùng chính hạ tầng AI làm kênh liên lạc.
- Để ý dấu hiệu bất thường: Claude Code chạy với tham số dòng lệnh lạ, hoặc lượng dữ liệu đẩy lên API khác hẳn ngày thường.
Nếu cần đưa khoá cho một script, cách an toàn hơn là đọc từ trình quản lý mật khẩu ngay lúc chạy thay vì lưu sẵn. Ví dụ với 1Password CLI:
# Khoá chỉ tồn tại trong tiến trình con, không nằm trong file hay lịch sử shell
ANTHROPIC_API_KEY="$(op read 'op://Dev/claude-script/credential')" python3 tom_tat_log.py
Giải thích: op read lấy giá trị từ kho 1Password theo đường dẫn op://kho/mục/trường (ở đây là tên ví dụ, bạn đặt theo kho của mình). Gán biến ngay trước lệnh khiến biến chỉ có hiệu lực cho đúng lệnh python3 đó. Lệnh vẫn hiện trong lịch sử shell, nhưng chỉ là đường dẫn tới kho, không phải khoá thật. Bạn dùng Bitwarden hay trình quản lý khác thì thay bằng lệnh tương ứng.
Nếu bạn nghi khoá đã lộ (từng commit nhầm lên GitHub, máy nhiễm mã độc, cài nhầm extension lạ), hãy vào Claude Console, xoá khoá cũ và tạo khoá mới trước rồi mới dọn dẹp. mmo.vn có hướng dẫn chi tiết cách rà repo trong bài lộ API key, mật khẩu qua AI coding agent.
MCP dễ dựng, khó cấp quyền
Phía còn lại của câu chuyện là khi bạn tự viết MCP server. Lập trình viên Sylwia Laskowska vừa minh hoạ điều này bằng một thử nghiệm vui: agent review code tên “Steve” được nối với một MCP server quản lý nhân sự dùng SQLite, có bốn công cụ, trong đó có file_complaint (ghi khiếu nại). Server mất khoảng 150 dòng, client khoảng 100 dòng.
Kết quả: Steve đọc đoạn code cố tình viết lỗi, rồi tự ghi một khiếu nại mức “severe” nhắm vào chính tác giả, dù file ghi rõ chỉ là demo. Chạy lại mà không đổi gì, Steve ghi thêm một khiếu nại nữa, lần này mức “legendary”. Một agent khác là Kiro (IDE của AWS) nối vào cùng server mà không cần tích hợp gì thêm, và ghi thêm hai khiếu nại. Bài học của tác giả: dựng MCP server là phần dễ; quyết định agent được làm gì mới là phần khó.

Nếu bạn vibe code một MCP server có công cụ ghi dữ liệu, ít nhất hãy kiểm tra quyền và chống làm trùng ngay trong server. Ví dụ với SDK Python chính thức, phiên bản 2.x (cài bằng pip install mcp):
from mcp.server.mcpserver import MCPServer
mcp = MCPServer("nhan-su")
MUC_TU_DONG = {"minor", "moderate"} # mức agent được tự ghi
da_ghi = set() # demo: thay bằng bảng trong database
@mcp.tool()
def file_complaint(developer: str, reason: str, severity: str, request_id: str) -> str:
"""Ghi một khiếu nại. Mức cao hơn moderate phải có người duyệt."""
if len(reason.strip()) < 5:
return "Từ chối: lý do quá ngắn."
if severity not in MUC_TU_DONG:
return "Đã chuyển cho người duyệt, chưa ghi."
if request_id in da_ghi:
return "Yêu cầu này đã được ghi trước đó, bỏ qua."
da_ghi.add(request_id)
# ghi vào database thật ở đây
return "Đã ghi khiếu nại."
if __name__ == "__main__":
mcp.run()
Giải thích: MCPServer là lớp dựng server trong gói mcp bản 2.x (bản 1.x gọi là FastMCP, nhập từ mcp.server.fastmcp), và @mcp.tool() biến hàm thành công cụ agent gọi được (chuỗi mô tả trong hàm là thứ agent đọc). Server tự kiểm tra ba điều thay vì tin agent: lý do đủ dài, mức nghiêm trọng nằm trong danh sách được phép tự ghi, và request_id chưa từng xử lý (chống chạy lại tạo bản ghi trùng). Biến da_ghi chỉ để minh hoạ; trong app thật, lưu vào database để không mất khi server khởi động lại.
Laskowska còn nhắc hai rủi ro khác: mô tả công cụ chỉ là lời tự giới thiệu của server, không chứng minh mã bên trong đáng tin; và kết quả trả về từ công cụ có thể chứa câu lệnh nhằm điều khiển agent (prompt injection). Một bình luận dưới bài gợi ý cách thực tế: việc đọc và việc đảo ngược được thì cho chạy tự do, còn việc ghi vào hệ thống thật thì để agent soạn sẵn, người bấm chạy.
Hiểu lầm phổ biến

“Ghi số phiên bản là đã khoá chặt.” Chỉ khoá được gói chính. Corelight cho thấy số phiên bản server giữ nguyên qua cả 15 môi trường, trong khi phụ thuộc bên dưới thay đổi.
“Dùng MCP thì công cụ tự an toàn.” MCP định nghĩa cách khám phá và gọi công cụ, kèm khung xác thực OAuth cho kết nối HTTP. Ai được làm gì, việc nào cần người duyệt, chạy lại có tạo bản ghi trùng không, đều do người viết server và ứng dụng quyết định.
“Mất API key chỉ tốn tiền.” Thử nghiệm của Darktrace cho thấy khoá có thể thành kênh ra lệnh và kênh rút dữ liệu, ngụy trang trong lưu lượng hợp lệ tới nhà cung cấp AI.
Bảy việc nên làm tuần này
Bạn không cần là chuyên gia bảo mật để làm những việc dưới đây. Mỗi việc mất vài phút đến nửa giờ.

1. Liệt kê MCP server đang dùng
Trong Claude Code, gõ /mcp để xem danh sách. Ghi lại mỗi server chạm được tới khoá, thư mục hay dịch vụ nào.
2. Tìm các dòng chạy bằng launcher
Mở .mcp.json của dự án và cấu hình MCP của Cursor, VS Code; tìm uvx, npx và @latest. Đây là những server có thể kéo mã mới mỗi lần mở phiên.
3. Đóng băng server đang giữ khoá
Ưu tiên server có token GitHub, database, cloud. Làm theo năm bước ở trên; với server npm, cài một lần bằng npm ci từ package-lock.json rồi chạy file đã cài.
4. Thu hẹp quyền token của server
Nếu server chỉ cần đọc, cấp token chỉ đọc; đặt hạn dùng cho token. Corelight khuyên mỗi server chỉ có quyền đúng với công cụ nó cung cấp.
5. Đổi API key nếu có nghi ngờ
Xoá khoá cũ trong Claude Console, tạo khoá mới, cập nhật nơi dùng. Đổi trước, dọn dẹp sau.
6. Bật hỏi trước thao tác ghi
Đừng cho agent tự ghi vào hệ thống thật. Giữ bước phê duyệt cho lệnh xoá, gửi, triển khai.
7. Hẹn lịch xem cập nhật
Chọn một ngày cố định mỗi tháng để xem bản mới của các server đã đóng băng, đọc thay đổi rồi mới tạo lại lock.
| Tiêu chí | Chạy bằng uvx, npx | Đóng băng |
|---|---|---|
| Cài đặt | Một dòng cấu hình | Vài lệnh, làm một lần |
| Phụ thuộc | Có thể đổi khi dựng lại | Khớp ngày cài qua 457 lần chạy |
| Khởi động | 4 đến 11 giây | Khoảng 2 giây |
| Cập nhật | Tự động, khó kiểm soát | Bạn tự xem và cập nhật |
Câu hỏi thường gặp
Tôi chỉ dùng MCP server của hãng lớn, có cần lo không?
Có, ở mức độ khác. Corelight khảo sát cả server trong danh mục của nhà cung cấp, và 23 trên 35 server có cách cài khuyến nghị kéo phụ thuộc từ kho công khai. Server của hãng lớn ít khả năng bị chiếm hơn, nhưng thư viện bên dưới vẫn đến từ cộng đồng.
Đây có phải lỗ hổng của Claude không?
Darktrace nói rõ kỹ thuật memory store không dựa vào lỗ hổng nào của nền tảng Claude, chưa thấy dùng ngoài thực tế và đã chia sẻ với Anthropic trước khi công bố. Điều kiện đầu tiên là kẻ tấn công phải có API key của bạn.
Dùng Cursor hay Copilot thay vì Claude Code thì có khác?
Bài học về MCP server áp dụng cho mọi trợ lý dùng MCP, vì cùng cơ chế khởi chạy server. Phần memory store là thử nghiệm riêng trên Claude, nhưng Darktrace lưu ý endpoint tải file dùng để rút dữ liệu cũng có bản tương đương ở OpenAI.
Đóng băng server rồi có bỏ lỡ bản vá bảo mật không?
Có thể, nếu bạn quên cập nhật. Vì vậy đóng băng phải đi kèm lịch xem lại định kỳ và một người chịu trách nhiệm tạo lại lock.
Làm sao biết API key của mình đã bị dùng lén?
Xem mục Usage và nhật ký trong Claude Console để tìm mức dùng bất thường, và kiểm tra danh sách memory store, file trong workspace có thứ bạn không tạo. Nghi ngờ thì đổi khoá trước.
Kết luận
Hai nghiên cứu tuần này cùng nhắc một điều: trợ lý lập trình AI mạnh tới đâu thì những thứ bạn cắm vào nó, từ MCP server tới API key, cũng quan trọng tới đó. Với người vibe code, ba việc đáng làm ngay là đóng băng các MCP server đang giữ khoá, chuyển sang đăng nhập OAuth hoặc khoá ngắn hạn quyền hẹp, và giữ bước người duyệt cho mọi thao tác ghi vào hệ thống thật.
Bạn đang dùng bao nhiêu MCP server, và có server nào chạy bằng @latest không? Chia sẻ ở phần bình luận để mọi người cùng rà, và theo dõi mmo.vn để cập nhật kiến thức lập trình AI an toàn mỗi tuần.


