ASVS 5.0 V6.4.1 requires that any password or activation code your system generates for a new account is created with a secure random generator, follows your password policy, expires quickly or after first use, and is never allowed to stay as the user's real password. It is a Level 1 requirement, so every application is expected to meet it.
Why it matters
Onboarding is where weak secrets hide. Admin created accounts with a shared "Welcome123", activation codes built from a timestamp, and temporary passwords that stay valid for months all give an attacker a direct way in. Anyone who can guess or see the secret (a forwarded email, a support ticket, a log line) owns the account.
How to implement it
Use your platform's cryptographic random source, store only a hash of the secret, set an expiry, and force a change at first login.
import secrets
import hashlib
from datetime import datetime, timedelta, timezone
def issue_activation(user_id: str):
token = secrets.token_urlsafe(32) # 256 bits from the OS CSPRNG
digest = hashlib.sha256(token.encode()).hexdigest()
db.activation.insert(
user_id=user_id,
token_hash=digest,
expires_at=datetime.now(timezone.utc) + timedelta(hours=24),
used_at=None,
)
return token # sent once, never stored in plain text
def redeem(token: str, new_password: str):
digest = hashlib.sha256(token.encode()).hexdigest()
row = db.activation.find(token_hash=digest)
if not row or row.used_at or row.expires_at < datetime.now(timezone.utc):
raise InvalidToken()
set_password(row.user_id, new_password) # runs the normal password policy
db.activation.mark_used(row.id)
Rules to enforce in code:
- Prefer activation links over emailed passwords. If a generated password is unavoidable, make it long and random, and mark the account
must_change_password. - The temporary secret may only authenticate the "set your password" step, not the rest of the app.
- Expiry in hours or days, and single use.
- Run the same password policy on the password the user picks.
How to test it
- Generate 1,000 codes and check for patterns, duplicates and sequential values.
- Use a code once, then try it again. It must fail.
- Wait past expiry (or move the clock in a test) and try it. It must fail.
- Log in with a temporary password and try to reach any page besides the change form. You should be blocked.
- Search the database for plain text initial secrets.
Common mistakes
- Using
Math.random(),rand()or a time seeded generator. - Storing the code in clear text so support can "resend" it.
- Letting the initial password remain valid after the user logs in.
- A default password that is the same for every new account.
- Never expiring unused invitations.
Try it yourself
Hard coded default credentials in source are a close cousin of this problem. A secrets scan finds them before release.
Click through it at your own pace, or open it full screen.
Quick check
Can an activation code be valid for 30 days?
The requirement says a short period or first use. Thirty days is hard to defend. Hours to a few days with single use is the usual choice.
Why store a hash of the code?
A database leak would otherwise hand out working activation links. A SHA-256 hash of a 256 bit random token is enough because the token cannot be guessed.