์ปจํ
์คํธ ๋ธ๋ก
| Key |
Value |
| Category |
frontend |
| Checklist |
ISS-UI-R5 โ External links without rel="noopener noreferrer" (target="_blank") |
| Priority |
P1 ๐ |
| Scan Date |
2026-04-16 |
| Flagged By |
@code-review |
์์ฝ
- WHAT:
<a target=\"_blank\"> ๋ ๊ตฐ๋ฐ์ rel=\"noopener noreferrer\" ๋๋ฝ + window.open(url, \"_blank\") ํ ๊ตฐ๋ฐ์ \"noopener,noreferrer\" ์ธ ๋ฒ์งธ ์ธ์ ๋๋ฝ โ ์ ํญ์ด window.opener๋ฅผ ํตํด ์๋ณธ ํ์ด์ง ์ ์ด ๊ฐ๋ฅ
- WHY: tabnapping ๊ณต๊ฒฉ ๋ฒกํฐ. ์ฌ์ฉ์๊ฐ ์ธ๋ถ ๋งํฌ ํด๋ฆญ ํ ์ ํญ JS๊ฐ
window.opener.location = \"phishing-url\"๋ก ์๋ณธ ํญ์ ํผ์ฑ ํ์ด์ง๋ก ์ ํ ๊ฐ๋ฅ
- WHERE:
frontend/src/features/chat/components/thread/ThreadScrollUtils.tsx:61-66, frontend/src/features/chat/components/agent-inbox/components/ThreadActionsView.tsx:108
- SEVERITY: HIGH โ ํฌ๋ก์ค ์ฌ์ดํธ ๊ณต๊ฒฉ ๋ฒกํฐ
Evidence
| # |
File |
Line |
Finding |
Flagged By |
Confidence |
| 1 |
frontend/src/features/chat/components/thread/ThreadScrollUtils.tsx |
61-66 |
<a target=\"_blank\">์ rel ์์ฑ ์์ (GitHub ๋งํฌ) |
@code-review |
High |
| 2 |
frontend/src/features/chat/components/agent-inbox/components/ThreadActionsView.tsx |
108 |
window.open(studioUrl, \"_blank\") โ \"noopener,noreferrer\" ์ธ ๋ฒ์งธ ์ธ์ ๋๋ฝ |
@code-review |
High |
| 3 |
(PASS ์ฐธ๊ณ ) MainLayoutClient.tsx:250-251, GenericInterrupt.tsx:30-31 |
โ |
๋ค๋ฅธ ์ธ๋ถ ๋งํฌ๋ ์ฌ๋ฐ๋ฅด๊ฒ rel=\"noopener noreferrer\" ์ค์ ๋จ โ ์ผ๊ด์ฑ ํ์ |
@code-review |
High |
์ํฅ ๋ถ์
์ํฅ ๋ฒ์
- ์ฑํ
UI ๋ด GitHub ๋งํฌ ํด๋ฆญํ๋ ๋ชจ๋ ์ฌ์ฉ์
- Agent Inbox์์ LangGraph Studio ์ ์ฐฝ ์ฌ๋ admin/๊ฐ๋ฐ์
์ฅ์ ์๋๋ฆฌ์ค
- ๊ณต๊ฒฉ์๊ฐ ํ๋กฌํํธ ์ธ์ ์
์ผ๋ก LangGraph ์๋ต์ด ์
์ฑ ์ธ๋ถ ๋งํฌ๋ฅผ ํฌํจํ๊ฒ ์ ๋ (๋๋ GitHub ์ด์ ๋ณธ๋ฌธ์ ์กฐ์)
- ์ฌ์ฉ์๊ฐ ๋งํฌ ํด๋ฆญ โ ์ ํญ์ ์
์ฑ ํ์ด์ง ๋ก๋
- ์
์ฑ ํ์ด์ง์ JS๊ฐ
window.opener.location = \"https://phishing-clone.com/login\" ์คํ
- ์ฌ์ฉ์๊ฐ ๊ธฐ์กด ํญ์ผ๋ก ๋์์ค๋ฉด phishing ํ์ด์ง โ ์๊ฒฉ์ฆ๋ช
์
๋ ฅ ์ ํ์ทจ
๊ธด๊ธ๋
- ๋ค๋ฅธ ์ธ๋ถ ๋งํฌ๋ค์ ์ด๋ฏธ
noopener noreferrer๋ฅผ ์ฐ๊ณ ์์ด ์ผ๊ด์ฑ ๋ถ์กฑ
- ์์ ๋น์ฉ ๊ทนํ ๋ฎ์ (๊ฐ ํ์ผ 1-2์ค)
์ ์ ํด๊ฒฐ ๋ฐฉ์
์ ๊ทผ ๋ฐฉ๋ฒ
ThreadScrollUtils.tsx:61-66:
// ๋ณ๊ฒฝ ์
<a href={...} target=\"_blank\">...
// ๋ณ๊ฒฝ ํ
<a href={...} target=\"_blank\" rel=\"noopener noreferrer\">...
ThreadActionsView.tsx:108:
// ๋ณ๊ฒฝ ์
window.open(studioUrl, \"_blank\");
// ๋ณ๊ฒฝ ํ
window.open(studioUrl, \"_blank\", \"noopener,noreferrer\");
ESLint ๊ท์น react/jsx-no-target-blank๋ฅผ ํ์ฑํํ์ฌ ์ฌ๋ฐ ๋ฐฉ์ง:
// frontend/eslint.config.js
rules: {
\"react/jsx-no-target-blank\": \"error\",
}
๋์
- ๋ผ์ฐํฐ ๊ธฐ๋ฐ ํธ๋ค๋ฌ: ์ธ๋ถ ๋งํฌ๋ฅผ Next.js API๋ก ํ๋ก์ โ ์ค์ฝํ ๊ณผ๋
- ์ฌ์ฉ์์๊ฒ "์ ์ฐฝ ์ด๊ธฐ" ๊ฒฝ๊ณ : UX ์ ํ
์์ฉ ๊ธฐ์ค
์ฐธ์กฐ
์ฌํ ๋ฐฉ๋ฒ
์ฌ์ ์กฐ๊ฑด
- ๋ก์ปฌ dev ์๋ฒ ์คํ (
pnpm dev)
- ์ฑํ
UI ์ ๊ทผ ๊ฐ๋ฅ
๋จ๊ณ
- ์ฑํ
ํญ์ GitHub ๋งํฌ ํ์ธ (ThreadScrollUtils)
- DevTools๋ก
<a> ์๋ฆฌ๋จผํธ์ ์์ฑ ํ์ธ
rel ์์ฑ ์กด์ฌ ์ฌ๋ถ ํ์ธ
๊ธฐ๋ ๊ฒฐ๊ณผ
rel=\"noopener noreferrer\" ์กด์ฌ
์ค์ ๊ฒฐ๊ณผ
rel ์์ฑ ์์ โ tabnapping ๊ฐ๋ฅ
๊ด๋ จ ์ฝ๋ ์ปจํ
์คํธ
| File |
Role |
Relevance |
frontend/src/features/chat/components/thread/ThreadScrollUtils.tsx |
์ฑํ
์คํฌ๋กค ์ ํธ + ๋งํฌ |
์์ ๋์ |
frontend/src/features/chat/components/agent-inbox/components/ThreadActionsView.tsx |
Agent Inbox ์ก์
๋ทฐ |
์์ ๋์ |
frontend/eslint.config.js |
ESLint ์ค์ |
๊ท์น ํ์ฑํ |
Detected by oh-my-braincrew `omb:issue` scan
Category: frontend | Scan date: 2026-04-16
`omb-issue-scan category=frontend checklist=ISS-UI-R5`
์ปจํ ์คํธ ๋ธ๋ก
ISS-UI-R5โ External links without rel="noopener noreferrer" (target="_blank")์์ฝ
<a target=\"_blank\">๋ ๊ตฐ๋ฐ์rel=\"noopener noreferrer\"๋๋ฝ +window.open(url, \"_blank\")ํ ๊ตฐ๋ฐ์\"noopener,noreferrer\"์ธ ๋ฒ์งธ ์ธ์ ๋๋ฝ โ ์ ํญ์ดwindow.opener๋ฅผ ํตํด ์๋ณธ ํ์ด์ง ์ ์ด ๊ฐ๋ฅwindow.opener.location = \"phishing-url\"๋ก ์๋ณธ ํญ์ ํผ์ฑ ํ์ด์ง๋ก ์ ํ ๊ฐ๋ฅfrontend/src/features/chat/components/thread/ThreadScrollUtils.tsx:61-66,frontend/src/features/chat/components/agent-inbox/components/ThreadActionsView.tsx:108Evidence
frontend/src/features/chat/components/thread/ThreadScrollUtils.tsx<a target=\"_blank\">์rel์์ฑ ์์ (GitHub ๋งํฌ)frontend/src/features/chat/components/agent-inbox/components/ThreadActionsView.tsxwindow.open(studioUrl, \"_blank\")โ\"noopener,noreferrer\"์ธ ๋ฒ์งธ ์ธ์ ๋๋ฝMainLayoutClient.tsx:250-251,GenericInterrupt.tsx:30-31rel=\"noopener noreferrer\"์ค์ ๋จ โ ์ผ๊ด์ฑ ํ์์ํฅ ๋ถ์
์ํฅ ๋ฒ์
์ฅ์ ์๋๋ฆฌ์ค
window.opener.location = \"https://phishing-clone.com/login\"์คํ๊ธด๊ธ๋
noopener noreferrer๋ฅผ ์ฐ๊ณ ์์ด ์ผ๊ด์ฑ ๋ถ์กฑ์ ์ ํด๊ฒฐ ๋ฐฉ์
์ ๊ทผ ๋ฐฉ๋ฒ
ThreadScrollUtils.tsx:61-66:
ThreadActionsView.tsx:108:
ESLint ๊ท์น
react/jsx-no-target-blank๋ฅผ ํ์ฑํํ์ฌ ์ฌ๋ฐ ๋ฐฉ์ง:๋์
์์ฉ ๊ธฐ์ค
eslint.config.js์react/jsx-no-target-blank: \"error\"์ถ๊ฐcd frontend && pnpm lintํต๊ณผtarget=\"_blank\"+ ๋์ผ ๋ผ์ธ์rel=์๋ ๊ฒฝ์ฐ 0๊ฑด ํ์ธcd frontend && pnpm lint && pnpm test์ฐธ์กฐ
์ฌํ ๋ฐฉ๋ฒ
์ฌ์ ์กฐ๊ฑด
pnpm dev)๋จ๊ณ
<a>์๋ฆฌ๋จผํธ์ ์์ฑ ํ์ธrel์์ฑ ์กด์ฌ ์ฌ๋ถ ํ์ธ๊ธฐ๋ ๊ฒฐ๊ณผ
rel=\"noopener noreferrer\"์กด์ฌ์ค์ ๊ฒฐ๊ณผ
rel์์ฑ ์์ โ tabnapping ๊ฐ๋ฅ๊ด๋ จ ์ฝ๋ ์ปจํ ์คํธ
frontend/src/features/chat/components/thread/ThreadScrollUtils.tsxfrontend/src/features/chat/components/agent-inbox/components/ThreadActionsView.tsxfrontend/eslint.config.js