Safeguard
Application Security•

ASVS 5.0 V6.4.1: Secure Initial Passwords and Activation Codes

System generated first passwords and activation codes must be random, policy compliant, short lived or single use, and never become the long term password. Level 1.

Safeguard Security Team
3 min read

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

  1. Generate 1,000 codes and check for patterns, duplicates and sequential values.
  2. Use a code once, then try it again. It must fail.
  3. Wait past expiry (or move the clock in a test) and try it. It must fail.
  4. Log in with a temporary password and try to reach any page besides the change form. You should be blocked.
  5. 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.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.