Claude Code나 Cursor 같은 코딩 에이전트, 요즘 많이 쓰죠.
저도 매일 써요. 헤츠너 서버에 도커로 띄워놓고, 권한 확인도 건너뛰고 알아서 명령을 실행하게 해놨거든요. 편해요. 진짜 편한데.
근데 얼마 전에 어떤 개발자가 쓴 글을 보고 등골이 좀 서늘해졌어요. 딱 한 문장이 머리에 박혔거든요.
"bash를 실행할 수 있는 코딩 에이전트는, 곧 당신 컴퓨터에 열린 원격 셸이다."
어? 이게 무슨 말이죠? 오늘은 이 얘기예요. AI로 코딩하는 분이라면 5분만 투자해서 꼭 확인해봐야 할 게 있어요.
솔직히 저도 이거 읽기 전엔 "에이전트가 내 명령대로 움직이는 편한 도구" 정도로만 생각했거든요. 근데 관점을 바꿔야 하더라고요.
원격 셸이라는 게 왜 무서운 말이냐면
먼저 용어부터 풀게요.
원격 셸(remote shell)은 멀리서 내 컴퓨터에 명령을 내릴 수 있는 통로예요. 해커들이 남의 컴퓨터를 장악할 때 제일 갖고 싶어 하는 게 이거예요. 셸을 하나 열면 그 컴퓨터에서 뭐든 할 수 있거든요. 파일 읽고, 지우고, 비밀번호 빼가고.
그럼 코딩 에이전트가 왜 원격 셸이냐고요?
생각해보세요. 에이전트는 내 컴퓨터에서 bash 명령을 실행할 수 있어요. 파일도 읽고, 명령도 돌리고. 그게 에이전트의 핵심 기능이잖아요. 근데 이거, 방향을 뒤집으면 **"외부에서 내 컴퓨터에 명령을 흘려보낼 수 있는 통로"**가 이미 열려 있다는 뜻이에요.
누가 설계 의도로 그렇게 만든 게 아니에요. 기능이 그런 모양이면, 위협 모델도 자동으로 그렇게 되는 거예요. 문을 편하라고 달았는데, 그 문으로 도둑도 들어올 수 있는 거죠.
그리고 이건 새로운 위협이 아니에요. 웹 세계가 지난 20년간 "localhost에 열린 프로그램"으로 당해온 실수들이 그대로 적용돼요. 브라우저를 통한 공격, DNS 리바인딩, curl | bash… 다 이미 겪고 기록해둔 것들이에요.
제일 무서운 건 "아무 사이트나 방문했을 뿐인데"
여기서 진짜 소름 돋는 시나리오가 하나 있어요. **브라우저 드라이브바이(drive-by)**라는 거예요.
이게 뭐냐면요. 에이전트가 명령을 받으려고 보통 로컬에 포트를 하나 열어둬요. 127.0.0.1, 그러니까 내 컴퓨터 안에서만 접근되는 주소로요. "내부 전용이니까 안전하겠지" 싶잖아요?
근데 여기 함정이 있어요.
당신이 그냥 웹 서핑을 하다가 어떤 악성 웹페이지에 들어갔다고 쳐요. 그 페이지가 자바스크립트로 127.0.0.1의 그 포트를 콕 찔러볼 수 있어요. 브라우저에서 실행되는 코드거든요. 그 코드가 당신 컴퓨터의 로컬 주소로 요청을 보내는 거예요.
만약 에이전트가 "로컬에서 온 요청이니까 통과"라고 처리하면요? 악성 사이트가 당신 컴퓨터에서 명령을 실행할 수 있게 돼요. 당신은 그냥 링크 하나 클릭했을 뿐인데.
어? 이거 이상하죠? 내부 전용 포트인데 왜 외부 사이트가 접근돼요?
이게 localhost 프로그램의 20년 묵은 함정이에요. 브라우저가 127.0.0.1로 요청을 보내면, 그것도 "로컬 요청"으로 보이거든요. 실제로는 악성 페이지가 시킨 건데도요.

"나쁜 명령어를 막으면 되잖아?" — 이게 안 통해요
여기서 많은 사람이 이렇게 생각해요. "그럼 위험한 명령어를 걸러내면 되지 않나?"
rm -rf 같은 거 들어오면 막고, curl 들어오면 막고. 명령어 문자열을 검사해서 나쁜 걸 차단하는 거죠.
근데 원저자가 인용한 문장이 아주 날카로워요.
"텍스트 명령어 필터링은 기도(thoughts and prayers)에 불과하다."
무슨 말이냐면, 문자열로 막는 건 그냥 "제발 안 뚫리게 해주세요" 하고 비는 거랑 똑같다는 거예요. 왜냐면 우회할 방법이 너무 많거든요.
몇 개만 볼까요.
- 명령어를 base64로 인코딩해서 넣고 실행 시점에 디코딩하기
- 파이프(|)로 다른 명령에 넘기기
- 히어독(heredoc)으로 여러 줄에 쪼개 넣기
- python3 -c로 파이썬 코드 안에 숨기기
- 절대 경로로 우회하기
이거 다 문자열 필터를 그냥 걸어서 지나가요. 나쁜 단어를 100개 막으면 101번째 방법이 나와요. 끝이 없어요.
비유하자면, 공항 검색대에서 "칼"이라고 적힌 물건만 압수하는 거예요. 근데 누가 칼에 "숟가락"이라고 써 붙이면요? 통과돼요. 이름표 검사로는 절대 못 막아요.
진짜 해법은 더 좋은 정규식이 아니에요. 문자열이 절대 건드릴 수 없는 두 개의 경계예요.
방어의 핵심은 딱 두 가지 질문
원저자가 정리한 게 명쾌해요. 방어는 결국 이 두 가지로 귀결된대요.
첫째, 누가 물어볼 수 있는가 (네트워크).
악성 웹페이지가 못 흉내 내는 신호가 하나 있어요. Origin 헤더예요. 브라우저는 다른 사이트로 요청을 보낼 때 자기 출처를 Origin 헤더에 반드시 담아요. 그리고 이건 페이지가 위조를 못 해요.
반면에 진짜 로컬 도구들(CLI, 에디터 같은)은 Origin을 안 보내요. 그러니까 규칙이 간단해져요. Origin이 붙어 있는데 허용 목록에 없으면? 거절. 이 한 줄로 브라우저 드라이브바이가 통째로 막혀요.
여기에 하나 더. DNS 리바인딩이라는 우회가 있어서 Host 헤더도 같이 검사해야 해요. 로컬 주소가 아닌 Host로 온 요청은 거절하는 거죠.
그리고 중요한 거. 읽기도 유출이에요. 명령 실행만 막으면 될 것 같죠? 아니에요. 대화 기록이나 로그를 그냥 읽어가는 것도 정보 유출이에요. 그러니까 읽기 경로도 쓰기만큼 똑같이 막아야 해요.
둘째, 프로세스가 뭘 할 수 있는가 (OS 샌드박스).
여기가 솔직한 부분이에요. bash나 python3 같은 인터프리터를 한 번 허용하면, 사실상 "아무 코드나 실행해도 됨"을 허용한 거예요. 작업 폴더를 지정해둬도 소용없어요. 그 안에서 ~/.ssh/id_rsa(SSH 비밀키) 읽는 거 못 막아요.
그래서 문자열이 아니라 OS 레벨에서 가둬야 해요. macOS는 Seatbelt, 리눅스는 bubblewrap 같은 샌드박스로요. 프로세스가 읽고 쓸 수 있는 범위를 OS가 강제로 제한하는 거예요. 심지어 네트워크 접근 자체를 끊을 수도 있고요.
한마디로, 허용 목록은 "어떤 프로그램을 켤까"를 정하고, OS는 "그 프로그램이 뭘 만질 수 있나"를 정하는 거예요. 이 둘은 층이 다르고, 둘 다 필요해요.
5분이면 되는 자가 점검 4가지
원저자가 준 체크리스트가 실용적이라 그대로 가져왔어요. 지금 쓰는 에이전트 도구에 이 네 가지를 물어보세요.
1. TCP 포트를 여는가? 127.0.0.1인가, 0.0.0.0인가? 0.0.0.0이면 외부 네트워크 전체에 열려 있는 거예요. 훨씬 위험해요. 반드시 127.0.0.1이어야 해요.
2. 아무 웹사이트나 그 포트를 fetch()해서 응답을 읽을 수 있는가? 아무 페이지나 열어서 개발자도구(F12)로 그 포트에 요청을 던져보세요. 응답이 오면 문제예요.
3. "bash 허용"이 검사하는 게 명령어 문자열인가, 실행 파일인가? 문자열을 검사한다면 위에서 말한 그 기도 방식이에요. 실행 파일(바이너리) 단위로 막아야 안전해요.
4. 내가 모델을 고르기도 전에 원격 모델에 접속하는가? 시작하자마자 외부로 뭔가 보낸다면, 그게 뭘 보내는지 알 수가 없어요.
답이 마음에 안 든다면, 저랑 같은 처지인 거예요.
저는 이걸 보고 제 서버 설정부터 열어봤어요
솔직히 말하면, 이 글 읽고 제 헤츠너 서버 설정을 바로 열어봤어요.
저는 Claude Code를 도커 컨테이너 안에서 돌려요. 그리고 이게 결과적으로 저를 살렸더라고요.
왜냐면 컨테이너 자체가 일종의 샌드박스거든요. 컨테이너 안의 프로세스는 기본적으로 호스트 서버의 파일 시스템 전체를 못 봐요. 제가 마운트해준 작업 폴더만 보이죠. 그러니까 위에서 말한 "인터프리터가 ~/.ssh 읽어가는" 문제가, 컨테이너 밖 호스트의 SSH 키에는 안 닿는 거예요.
근데 완벽하진 않았어요. 컨테이너 안에도 크리덴셜이 좀 있었고, 무엇보다 제가 컨테이너를 non-root로 안 돌리고 있던 자리가 있더라고요. 컨테이너가 뚫리면 그 권한이 그대로 새는 거죠. 그날 바로 고쳤어요.
이게 포인트예요. 에이전트를 격리된 환경에서 돌리는 것, 그게 문자열 필터 백 개보다 나아요. 도커든, 전용 사용자 계정이든, 별도 가상머신이든요. "이 프로세스가 최악의 경우 뭘 만질 수 있나"의 범위를 물리적으로 줄여두는 거예요.
권한 확인을 건너뛰고 자동으로 굴리는 게 편하긴 해요. 근데 그 편함의 대가로, 격리만큼은 절대 양보하면 안 되는 거였어요.
결국 핵심은, 에이전트를 "손님"이 아니라 "열린 문"으로 보세요
정리하면 이래요.
- 코딩 에이전트는 편한 도구가 아니라 localhost에 열린 원격 셸이에요. 그 관점으로 봐야 해요.
- 나쁜 명령어를 문자열로 막는 건 기도예요. 안 통해요.
- 진짜 방어는 두 경계. 누가 물어볼 수 있나(네트워크 검증), 프로세스가 뭘 만질 수 있나(OS 격리).
- 읽기도 유출이에요. 쓰기만큼 막으세요.
- 그리고 무엇보다, 격리된 환경에서 돌리세요. 도커, 전용 계정, 가상머신. 뭐든요.
솔직히 이거 겁주려는 글은 아니에요. 에이전트 쓰지 말라는 것도 아니고요. 저도 계속 쓸 거예요. 다만 관점 하나만 바꾸자는 거예요.
한번 해보세요. 지금 쓰는 에이전트에 위 4가지 질문을 던져보는 거예요. 특히 2번, 아무 페이지나 열어서 개발자도구로 로컬 포트를 찔러보는 것. 5분이면 돼요. 뭔가 나올 거예요.
저는 다음 글에서 Claude Code를 도커로 안전하게 격리하는 실제 설정을, non-root 사용자부터 볼륨 마운트 범위까지 구체적으로 풀어볼 생각이에요.
'AI 인공지능' 카테고리의 다른 글
| "90% 자율" AI 에이전트, 사실은 61.6%짜리입니다 (0) | 2026.07.15 |
|---|---|
| AI 시대에 안 사라지는 일의 공통점, 하나로 정리됩니다 (1) | 2026.07.12 |
| AI 챗봇 78점 받았는데 위험하다? 평균 점수의 함정 (0) | 2026.07.12 |
| Claude Code 토큰, 나도 모르게 새고 있었다 — 실전에서 막은 3가지 (0) | 2026.07.11 |
| AI API 가격이 무너지고 있다는데, 우리 회사 LLM 비용은 얼마일까? (0) | 2026.07.07 |