APP-75Recommended
Mask sensitive values until people ask to see them
Show bank account numbers, government ID numbers and stored secrets masked, such as the last 4 characters. Send the full value only when a person with the permission presses Show, and log each request.
How to do it
The server sends only the masked form in lists and detail views, so the full value never sits in the page or its cached data. A Show button calls a separate endpoint that checks the permission, writes who asked and when to the audit log, and returns the value. Hide it again when the person leaves the screen. Replies carry nothing else the screen does not show, as return only the fields needed says. Card numbers never reach your servers at all under keep card numbers off your servers.
Examples
Python example
def masked(value: str) -> str:
return "•••• " + value[-4:]
@app.get("/customers/<customer_id>")
def customer_detail(customer_id):
customer = customers.get(current_user().account_id, customer_id)
return {"name": customer.name, "bank_account": masked(customer.bank_account)}
@app.post("/customers/<customer_id>/bank-account/reveal")
def reveal_bank_account(customer_id):
require_permission(current_user(), "customers.reveal_bank_account")
customer = customers.get(current_user().account_id, customer_id)
audit.write(actor=current_user().id, action="reveal_bank_account", target=customer.id)
return {"bank_account": customer.bank_account}
TypeScript example
export async function revealBankAccount(customerId: string, field: HTMLElement) {
const response = await fetch(`/customers/${customerId}/bank-account/reveal`, { method: 'POST' });
if (!response.ok) return showStatus('You do not have access to the full number.');
const { bank_account } = await response.json();
field.textContent = bank_account;
addEventListener('pagehide', () => { field.textContent = ''; }, { once: true });
}
How to check
Load a customer list and a detail page as a support user. The responses hold only the last 4 characters of each masked field. Pressing Show returns the full value and adds 1 audit entry. A user without the permission gets a 403.
Sources
Related rules
- APS-22 Return only the fields needed in Application security
- PAY-1 Choose a checkout that keeps you on SAQ A in Payments and billing
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/app-ui/data-views/mask-sensitive-values">Agent Wranglers web app interface playbook</a>. In code you write, add a comment next to it with the same link.