Answer Key
🇻🇳 Đáp án
Global / Layout (5)
🇻🇳 Toàn cục / Bố cục
-
Nav bar has no wrap/scroll handling and overlaps the logo on narrow viewports
🟢 Junior thường bỏ qua Chỉ test ở màn hình desktop rộng, không thu nhỏ cửa sổ hay test trên viewport điện thoại/tablet.
🔵 Senior hay phát hiện Luôn resize/responsive-test qua nhiều breakpoint và thiết bị thật trước khi báo pass. -
The "QA Bug Playground" logo link has cursor:default instead of a pointer
🟢 Junior thường bỏ qua Không để ý chi tiết nhỏ như con trỏ chuột — chỉ quan tâm click có hoạt động hay không.
🔵 Senior hay phát hiện Đánh giá cả affordance/UX: người dùng có nhận ra đây là link không, chứ không chỉ chức năng có chạy. -
Fixed footer with no body bottom-padding can cover the end of long pages
🟢 Junior thường bỏ qua Chỉ xem trang ngắn hoặc không cuộn xuống hẳn cuối trang dài.
🔵 Senior hay phát hiện Luôn cuộn hết trang, đặc biệt các trang dài hoặc có nội dung động (danh sách, comment...). -
Footer text color fails WCAG contrast ratio against its background
🟢 Junior thường bỏ qua Không kiểm tra accessibility/độ tương phản màu, chỉ nhìn qua bằng mắt thấy "đọc được" là đủ.
🔵 Senior hay phát hiện Dùng công cụ (Lighthouse, axe, contrast checker) để verify accessibility theo chuẩn WCAG. -
No security headers set anywhere (CSP, X-Frame-Options, X-Content-Type-Options, HSTS)
🟢 Junior thường bỏ qua Không mở tab Network/Headers trong DevTools, chỉ quan tâm giao diện hiển thị đúng.
🔵 Senior hay phát hiện Luôn kiểm tra response headers — thiếu CSP/X-Frame-Options nghĩa là app có thể bị clickjacking hoặc XSS lan rộng hơn.
UI Bugs — /ui-bugs (17)
🇻🇳 Lỗi giao diện
-
"Place Order" button looks disabled (CSS opacity) but has no disabled attribute and is fully clickable
🟢 Junior thường bỏ qua Nhìn nút bị mờ đi là kết luận ngay "đã disable", không thử click thật vào nó.
🔵 Senior hay phát hiện Luôn thử click vào phần tử "trông có vẻ disabled" để xác nhận nó thực sự chặn hành động. -
Modal close (X) button is wired to a non-existent element, so it can never close the modal
🟢 Junior thường bỏ qua Test nhanh một lần, thấy modal mở được là coi như pass, không thử đóng lại.
🔵 Senior hay phát hiện Test đủ vòng đời của component: mở → tương tác → đóng → mở lại. -
Dropdown menu renders behind the card's clipped edge (overflow:hidden on the parent)
🟢 Junior thường bỏ qua Không kiểm tra dropdown/menu ở các vị trí hoặc kích thước container khác nhau.
🔵 Senior hay phát hiện Kiểm tra các phần tử overlay (dropdown, tooltip, modal) trong nhiều ngữ cảnh layout khác nhau. -
Tabs always show Tab 1's content regardless of which tab is clicked
🟢 Junior thường bỏ qua Chỉ click 1 tab rồi kết luận tính năng tab hoạt động bình thường.
🔵 Senior hay phát hiện Test lần lượt tất cả các tab/trạng thái, không suy luận kết quả từ một mẫu duy nhất. -
Star rating is off by one: clicking the 3rd star fills 4 stars
🟢 Junior thường bỏ qua Không đối chiếu số sao hiển thị với đúng vị trí đã click.
🔵 Senior hay phát hiện Test các giá trị biên (sao đầu tiên, giữa, cuối cùng) và so khớp chính xác kết quả mong đợi. -
"+1" / "-1" counter buttons are swapped: plus decrements, minus increments
🟢 Junior thường bỏ qua Chỉ click 1 nút, thấy số thay đổi là pass, không đọc kỹ số tăng hay giảm.
🔵 Senior hay phát hiện Luôn đối chiếu hành vi thực tế với nhãn nút — verify giá trị trước/sau mỗi thao tác. -
Accordion expands to a fixed max-height shorter than its content, clipping the text
🟢 Junior thường bỏ qua Test với nội dung mẫu ngắn, không thử nội dung dài như thực tế sẽ gặp.
🔵 Senior hay phát hiện Test với dữ liệu dài/thực tế (long-content testing), không chỉ dữ liệu mẫu ngắn gọn. -
Product image points at a non-existent file and has no alt text
🟢 Junior thường bỏ qua Không để ý ảnh vỡ nếu nó nhỏ, hoặc không nghĩ tới việc kiểm tra alt text.
🔵 Senior hay phát hiện Kiểm tra alt text cho accessibility và trải nghiệm khi ảnh không tải được. -
Password visibility toggle changes its own icon but never flips the input's type
🟢 Junior thường bỏ qua Chỉ nhìn icon con mắt đổi trạng thái, không kiểm tra input có thực sự hiển thị giá trị hay không.
🔵 Senior hay phát hiện Verify trạng thái thực sự thay đổi (type=text), chứ không chỉ verify icon trên UI. -
Toast notification auto-dismisses after 250ms and can render behind the header (z-index)
🟢 Junior thường bỏ qua Không đo thời gian hiển thị thực tế của thông báo, thấy "có xuất hiện" là pass.
🔵 Senior hay phát hiện Đo thời gian hiển thị, kiểm tra z-index/stacking context ở nhiều vị trí cuộn trang. -
Long unbroken order-reference text overflows its container, causing horizontal page scroll
🟢 Junior thường bỏ qua Test với text ngắn mẫu, không thử input dài bất thường.
🔵 Senior hay phát hiện Luôn test với input cực dài (long string) để phát hiện lỗi tràn layout. -
Pagination "Next" never clamps to the last page ("Page 7 of 3")
🟢 Junior thường bỏ qua Chỉ test lướt qua một hoặc hai trang đầu.
🔵 Senior hay phát hiện Test giá trị biên: trang đầu, trang cuối, và vượt quá giới hạn (boundary testing). -
Feedback submit button has no debounce/disable-on-click guard, so a fast double-click submits twice
🟢 Junior thường bỏ qua Chỉ click một lần chậm rãi, không test double-click hoặc mạng chậm.
🔵 Senior hay phát hiện Test double-submit/race condition bằng cách click nhanh liên tục để tìm lỗi trùng lặp. -
Explicit, inconsistent tabindex values scramble keyboard tab order
🟢 Junior thường bỏ qua Chỉ test bằng chuột, không bao giờ dùng bàn phím để điều hướng qua trang.
🔵 Senior hay phát hiện Test đầy đủ bằng bàn phím (Tab/Shift+Tab) và trải nghiệm screen reader cho accessibility. -
Clicking the table's "Price" header computes a sorted array but never re-renders it into the DOM
🟢 Junior thường bỏ qua Thấy icon mũi tên đổi hướng là kết luận sort hoạt động, không nhìn kỹ dữ liệu trong bảng.
🔵 Senior hay phát hiện Luôn đối chiếu dữ liệu thực tế hiển thị, không chỉ tin vào tín hiệu UI (icon/label). -
An input placed mid-page has autofocus, causing a disorienting scroll-jump on load
🟢 Junior thường bỏ qua Không để ý hành vi cuộn trang tự động khi trang vừa tải xong.
🔵 Senior hay phát hiện Đánh giá trải nghiệm tải trang đầu tiên (first-load UX), đặc biệt ảnh hưởng người dùng screen reader. -
"Load more" always appends the same hardcoded items instead of tracking an offset/cursor
🟢 Junior thường bỏ qua Click "Load more" một lần thấy có thêm item là pass, không click nhiều lần liên tục.
🔵 Senior hay phát hiện Test lặp lại hành động nhiều lần để phát hiện lỗi trùng lặp hoặc thiếu cơ chế phân trang.
Checkout / Cart — /checkout (6)
🇻🇳 Thanh toán / Giỏ hàng
-
Quantity field has no lower bound — 0 or negative values are accepted
🟢 Junior thường bỏ qua Chỉ test số lượng dương hợp lệ (1, 2, 3...).
🔵 Senior hay phát hiện Luôn test giá trị biên và giá trị phi lý: 0, số âm, số thập phân, ký tự chữ. -
An item marked "out of stock" is still fully purchasable — nothing disables the form
🟢 Junior thường bỏ qua Không đối chiếu trạng thái tồn kho hiển thị với hành vi thực tế của nút mua.
🔵 Senior hay phát hiện Kiểm tra tính nhất quán giữa dữ liệu hiển thị (business state) và hành vi thực tế cho phép của UI. -
Coupon discount stacks another 10% every time "Apply" is clicked, with no cap
🟢 Junior thường bỏ qua Áp mã giảm giá một lần, thấy giảm đúng % là pass.
🔵 Senior hay phát hiện Test click lặp lại nhiều lần trên cùng một hành động để tìm lỗi tích lũy (stacking bug). -
Totals are computed in plain floating-point with no rounding, producing artifacts like 59.970000000000006
🟢 Junior thường bỏ qua Không tự tính lại số tiền bằng máy tính để đối chiếu.
🔵 Senior hay phát hiện Luôn verify phép tính tiền bằng công cụ độc lập, đặc biệt với số thập phân/tiền tệ. -
Free-shipping banner uses total <= 50 instead of < 50, an off-by-one at exactly $50.00
🟢 Junior thường bỏ qua Test với số tiền rõ ràng trên hoặc dưới ngưỡng, không test đúng ngay tại ngưỡng.
🔵 Senior hay phát hiện Test chính xác tại giá trị biên (ví dụ đúng $50.00), không chỉ trên/dưới ngưỡng. -
The server accepts the client-submitted unit_price/total hidden fields instead of re-pricing from the catalog
🟢 Junior thường bỏ qua Không mở DevTools để xem/sửa các trường ẩn (hidden field) trước khi submit.
🔵 Senior hay phát hiện Luôn nghĩ theo góc nhìn kẻ tấn công: sửa hidden field, replay request bằng curl/Burp để kiểm tra server có tính lại giá không.
Form Validation — /validation (11)
🇻🇳 Kiểm tra dữ liệu nhập
-
Username is never required — empty string is accepted client- and server-side
🟢 Junior thường bỏ qua Chỉ test với dữ liệu hợp lệ đầy đủ, không thử để trống trường bắt buộc.
🔵 Senior hay phát hiện Luôn test bỏ trống từng trường required để xác nhận validation thực sự chặn được. -
Email regex only checks for "@", so "abc@d" passes
🟢 Junior thường bỏ qua Chỉ test một email hợp lệ dạng chuẩn (name@domain.com).
🔵 Senior hay phát hiện Test nhiều biến thể input gần-đúng định dạng để dò tìm regex yếu. -
Password label says "at least 8 characters" but only 4 is enforced (and no number required)
🟢 Junior thường bỏ qua Không đối chiếu chính xác giữa message/label hiển thị và hành vi thực tế được chấp nhận.
🔵 Senior hay phát hiện Đối chiếu từng câu chữ trong UI với hành vi backend thực tế — rule hiển thị phải khớp rule thực thi. -
Confirm-password is collected but never actually compared to the password
🟢 Junior thường bỏ qua Nhập hai mật khẩu giống nhau để test, không thử cố tình nhập khác nhau.
🔵 Senior hay phát hiện Test negative case: cố tình nhập sai lệch để xác nhận validation có thực sự so sánh hay không. -
Age field accepts negative numbers, decimals, or non-numeric junk — only "empty" is rejected
🟢 Junior thường bỏ qua Chỉ test tuổi hợp lý (18, 25...), không thử giá trị phi logic.
🔵 Senior hay phát hiện Test toàn bộ input biên: âm, thập phân, chữ, ký tự đặc biệt, giá trị cực lớn. -
Phone field claims "digits only" but nothing enforces it — letters are accepted
🟢 Junior thường bỏ qua Tin vào label "digits only" mà không thử nhập chữ để kiểm chứng.
🔵 Senior hay phát hiện Không bao giờ tin label/placeholder — luôn tự kiểm chứng bằng input thực tế. -
"I agree to terms" checkbox condition is inverted — submitting unchecked still succeeds
🟢 Junior thường bỏ qua Luôn tick checkbox trước khi submit theo thói quen, không thử để trống.
🔵 Senior hay phát hiện Test rõ từng nhánh boolean (checked/unchecked) — cả hai chiều đều phải được verify. -
Client-side validation never actually blocks anything (errors don't clear, and preventDefault is never called)
🟢 Junior thường bỏ qua Coi client validation và server validation là một, không phân biệt hai lớp kiểm tra riêng biệt.
🔵 Senior hay phát hiện Luôn test cả hai lớp riêng biệt: tắt JS hoặc gửi thẳng request để xác nhận server tự bảo vệ được. -
Leading/trailing whitespace on username is never trimmed (" admin" looks like a different account)
🟢 Junior thường bỏ qua Không thử input có khoảng trắng ở đầu hoặc cuối chuỗi.
🔵 Senior hay phát hiện Test input có whitespace/ký tự ẩn để phát hiện lỗi trùng lặp dữ liệu (" admin" khác "admin"). -
No length limit or Unicode normalization on username (accepts huge pastes, emoji, RTL text)
🟢 Junior thường bỏ qua Không thử input cực dài hoặc emoji/ký tự đặc biệt.
🔵 Senior hay phát hiện Test input Unicode, emoji, RTL text và input rất dài để tìm lỗi hiển thị/lưu trữ. -
The success banner echoes the submitted username back unescaped (reflected XSS)
🟢 Junior thường bỏ qua Chỉ test dữ liệu text thông thường, không thử payload HTML/JS.
🔵 Senior hay phát hiện Luôn thử payload XSS cơ bản (<script>, <img onerror>) ở mọi trường input được hiển thị lại.
SQL Injection & Data — /sqli (4)
🇻🇳 Chèn lệnh SQL & Dữ liệu
-
Login query is built with raw string concatenation (bypass: ' OR '1'='1' -- ); passwords are also stored in plaintext
🟢 Junior thường bỏ qua Chỉ test đăng nhập với tài khoản hợp lệ/sai theo cách thông thường.
🔵 Senior hay phát hiện Luôn thử payload SQL injection kinh điển trong các trường đăng nhập, và kiểm tra cách mật khẩu được lưu trữ. -
Product search is vulnerable to UNION-based extraction of the users table
🟢 Junior thường bỏ qua Chỉ test tìm kiếm với từ khóa sản phẩm thông thường.
🔵 Senior hay phát hiện Thử payload UNION SELECT để kiểm tra khả năng rò rỉ dữ liệu qua chức năng tìm kiếm. -
The username-availability check is a textbook blind boolean-based injection point
🟢 Junior thường bỏ qua Bỏ qua các API/endpoint "phụ" không hiển thị dữ liệu trực tiếp, cho là an toàn vì "không thấy gì".
🔵 Senior hay phát hiện Hiểu rằng một response chỉ trả true/false vẫn có thể bị khai thác qua blind injection. -
The last search term is echoed unescaped into the search box's value attribute (reflected XSS / attribute breakout)
🟢 Junior thường bỏ qua Chỉ kiểm tra input có hiển thị lại đúng giá trị đã gõ, không thử payload phá vỡ thuộc tính HTML.
🔵 Senior hay phát hiện Thử payload dạng "><script> để kiểm tra khả năng thoát khỏi thuộc tính HTML (attribute breakout).
XSS Guestbook — /xss (2)
🇻🇳 Sổ lưu bút dính XSS
-
Comment body is stored and re-rendered without any HTML-escaping (stored XSS)
🟢 Junior thường bỏ qua Test comment với nội dung text thường, không thử tag HTML/script.
🔵 Senior hay phát hiện Luôn thử payload XSS lưu trữ (stored XSS) ở mọi trường nội dung do người dùng nhập và hiển thị lại cho người khác. -
"Reset demo comments" is a destructive action exposed via a plain GET link with no CSRF protection
🟢 Junior thường bỏ qua Không để ý phương thức HTTP (GET/POST) được dùng cho một hành động xóa dữ liệu.
🔵 Senior hay phát hiện Luôn kiểm tra các hành động thay đổi dữ liệu phải dùng POST/DELETE có bảo vệ CSRF, không phải GET.
Broken Access Control / IDOR — /idor (2)
🇻🇳 Lỗi phân quyền / IDOR
-
Order lookup never verifies the order's user_id matches the logged-in user — sequential IDs are enumerable
🟢 Junior thường bỏ qua Chỉ test xem đúng đơn hàng của tài khoản mình đang đăng nhập.
🔵 Senior hay phát hiện Chủ động thử truy cập ID của người dùng khác (đổi ID trên URL) để kiểm tra authorization boundary. -
"Login" is just a spoofable ?as= URL query parameter — no real session or credential check
🟢 Junior thường bỏ qua Coi việc chuyển đổi user qua URL là tính năng bình thường của app demo, không đặt câu hỏi về cơ chế xác thực.
🔵 Senior hay phát hiện Luôn đặt câu hỏi: cơ chế xác thực có thực sự an toàn không, hay chỉ là "ảo giác" ở lớp giao diện.
Undocumented API — /api/* (3)
🇻🇳 API không tài liệu hóa
-
GET /api/orders serves every user's order history (incl. shipping addresses) with wide-open CORS and zero auth
🟢 Junior thường bỏ qua Không đoán/tìm các API endpoint không được liên kết từ giao diện.
🔵 Senior hay phát hiện Chủ động dò tìm endpoint ẩn (network tab, đoán theo REST convention) và kiểm tra CORS/auth trên từng API. -
GET /api/debug returns the raw error message and full stack trace to the client
🟢 Junior thường bỏ qua Không cố tình gửi input gây lỗi để xem phản hồi lỗi trông như thế nào.
🔵 Senior hay phát hiện Chủ động kích hoạt lỗi (invalid input, edge case) để kiểm tra thông tin nhạy cảm có bị rò rỉ qua error response không. -
No rate limiting anywhere — login, the username-availability check, etc. can all be brute-forced freely
🟢 Junior thường bỏ qua Không nghĩ đến việc test số lượng request lớn hoặc lặp lại liên tục.
🔵 Senior hay phát hiện Luôn đánh giá khả năng chống brute-force/rate limiting cho các endpoint nhạy cảm như đăng nhập.