Skip to content
Security HeadersPassword Autocomplete

Password Autocomplete: What the Browser Remembers and How to Mark Password Fields

Browsers offer to save and refill passwords unless the page says what each field is for. Here is what the autocomplete attribute can and cannot control, where a saved password does real harm, and how to mark sign-in, sign-up, reset and one-time fields.

Part 2 of 2From the Security Headers series

At a glance

CWE-522
Interpreter
The browser's password manager and form autofill
Required condition
A password field declares no purpose, and the page is used from a shared browser profile or sets passwords for other accounts.
Potential impact
A saved password fills in for the next person at the keyboard, or lands in a field that sets another account's password.
Primary defense
Give every password field the token for its job: current-password to sign in, new-password to set a password, off for one-time secrets.

Safe practice: use benign proof only, in a disposable local lab or on a system you are explicitly authorized to test.

On this page

Every major browser ships a password manager. When someone signs in, the browser offers to remember the credentials, and on the next visit it fills them back in. The page influences this through one attribute, autocomplete, which tells the browser what a field is for: the account's current password, a new one, or a value it should not remember at all. A password field without it leaves the browser to guess.

MITRE files the weakness as CWE-522, Insufficiently Protected Credentials, which OWASP Top 10:2025 maps to A06 Insecure Design. The risk is narrower than most entries on that list: the password stays in the user's browser, or the browser account it syncs to, and nobody on the network can reach it. It matters where one browser profile serves several people, and where a field that sets a password gets filled with the wrong one.

How it happens

The autocomplete attribute takes either on, off or a token that names the field's purpose. For password fields, three values matter:

Value What it declares What browsers do with it
current-password The account's existing password, on a sign-in form Offer to save it and fill it on the next visit
new-password A password being set: sign-up, change or an admin reset Avoid filling the saved password; may suggest a generated one
off A value that should not be remembered or offered again Skip storing and filling it, except that many browsers ignore it on login fields
Nothing Treated as on: autofill allowed, purpose unknown The browser decides from the shape of the form

Applications get this wrong by omission. A typical account area has password forms written at different times, and none of them say which is which:

<form method="post" action="/login">
  <input name="email" type="email">
  <input name="password" type="password">
  <button type="submit">Sign in</button>
</form>

<form method="post" action="/admin/users/42/password">
  <input name="password" type="password">
  <input name="confirm" type="password">
  <button type="submit">Set password</button>
</form>

The sign-in form gets by because it looks like one. The second form is the problem: nothing tells the browser that its fields set a password for someone else, so the browser can offer, or fill, the administrator's own saved password there.

A concrete walk-through: read the markup, then watch the browser

An authorized tester starts with the HTML the server sends for the admin reset page:

curl -s https://app.example/admin/users/42/password | grep -io '<input[^>]*type="password"[^>]*>'
<input name="password" type="password">
<input name="confirm" type="password">

Neither field declares a purpose. Next, in a browser profile where the test administrator's password is saved, the tester signs in and opens the same page. If the browser fills the saved password into the reset fields, or offers it in a dropdown, the defect is shown: submitting would give account 42 the administrator's password. The tester notes what the browser did and leaves the form unsubmitted.

The sign-in page gets the same check on a shared test profile: after one sign-in and sign-out, a second visit shows whether the browser fills the login form for whoever sits down next.

What an attacker gains

  • The next person at the keyboard. On a shared computer or browser profile, saved credentials fill the sign-in form for whoever comes next. Signing out of the site ends the session; it does not remove the password from the browser.
  • A password in the wrong field. On reset, sign-up and change forms without new-password, a saved password can land in a field that sets a password. An administrator who submits without noticing leaves another account protected by the administrator's own password.
  • Saved secrets that are not passwords. A PIN, recovery code or one-time code typed into a password field can be offered for saving like a password, so a value meant for one moment stays in the browser.

None of these can be triggered from the network. They matter for applications used from shared machines, kiosks and admin consoles, which is why the finding is a hardening item rather than an injection flaw.

Reading a SelfSec finding

The Password Autocomplete check is passive. After the crawl, each discovered URL is fetched again with a plain GET, and the returned HTML is searched for <input> tags whose type is password, in single or double quotes.

  • A tag passes only when it contains autocomplete="off" or autocomplete="new-password", in single or double quotes. Everything else is reported, including current-password, an unquoted autocomplete=off and an autocomplete attribute set only on the enclosing <form>.
  • Each password input without one of those values is reported on the URL that returned it, at medium severity, as CWE-522 under A06:2025 Insecure Design. The evidence is the <input> tag itself, with the request and response attached. SelfSec maps CWE-522 to ATT&CK T1552, Unsecured Credentials.
  • Only server-sent HTML is read. Password fields that JavaScript adds after the page loads are not checked, so review client-rendered forms by hand.
  • A sign-in field marked current-password is still reported, because only off and new-password ask the browser not to fill a saved password. Many browsers ignore off on login fields, so treat that finding as a question about where the form is used: keep current-password on a public site, and handle shared machines with the controls in the next section.

The fix: say what each password field is for

Mark every password field with the token for its job. A sign-in form pairs username with current-password, which lets password managers work as intended:

<form method="post" action="/login">
  <label for="email">Email</label>
  <input id="email" name="email" type="email" autocomplete="username" required>
  <label for="password">Password</label>
  <input id="password" name="password" type="password" autocomplete="current-password" required>
  <button type="submit">Sign in</button>
</form>

Every field that sets a password, on sign-up, change and admin reset forms alike, uses new-password, including the confirmation field. Browsers use it to avoid filling the saved password and to offer a generated one; it is a hint, so check the result in the browsers your users run:

<form method="post" action="/admin/users/42/password">
  <label for="new-password">New password for this user</label>
  <input id="new-password" name="password" type="password" autocomplete="new-password" minlength="12" required>
  <label for="confirm-password">Confirm new password</label>
  <input id="confirm-password" name="confirm" type="password" autocomplete="new-password" minlength="12" required>
  <button type="submit">Set password</button>
</form>

A PIN or recovery code that is masked as a password field uses off, which the HTML standard defines as a value the browser should not remember or offer again:

<label for="pin">Transaction PIN</label>
<input id="pin" name="pin" type="password" inputmode="numeric" autocomplete="off" required>

No markup removes a password the browser has already saved. Where several people share a machine, turn the browser's password manager off through its enterprise policy, or use guest or kiosk profiles that keep no saved data, and keep the application's own sessions short.

Fixes that do not hold

  • autocomplete="off" on a sign-in form as a security control: many modern browsers still offer to remember the login and fill it next time.
  • autocomplete="off" on the <form> only: browsers still offer to save login fields, and SelfSec checks each input tag, so the finding stays.
  • Blocking paste or swapping field types with script: it fights password managers and pushes users toward weaker, reused passwords. OWASP's Authentication Cheat Sheet recommends allowing paste into password fields.
  • Relying on sign-out: it ends the session on the server. The saved password stays in the browser.

A developer review checklist

  1. List every type="password" input in server templates and client components.
  2. Give sign-in forms autocomplete="username" and autocomplete="current-password".
  3. Give every new and confirmation field on sign-up, change and admin reset forms autocomplete="new-password".
  4. Give PINs and one-time secrets in password fields autocomplete="off".
  5. Allow paste, and never break password managers on purpose.
  6. For shared machines, disable saved passwords by browser policy, not by markup.

References

SelfSec scanner

Find Security Headers in your own app

Reading about the class is one thing. SelfSec tests for it against an application you are authorized to assess, and only calls it real when independent evidence agrees.

Find it Confirmed, not guessed 21 vulnerability modules, with the classical engine owning the verdict. Prove it Evidence you can re-read Every finding keeps the raw request, the response and the baseline it was measured against.
Join the launch list