T09 · Insecure Skill Coding Practices
- Location
references/circle-smart-account.md:55- Finding
Passkey Credential Objects Persisted in Browser localStorage
- Content
View full analysis
Vulnerability Details
File Location:
references/circle-smart-account.md:55andreferences/circle-smart-account.md:67
Vulnerability Type: Sensitive authentication data stored in script-accessible browser storage
Risk Level: MediumVulnerable Code
typescript const credential = await toWebAuthnCredential({ transport: passkeyTransport, mode: WebAuthnMode.Register, username: 'alice', }) // Persist credential so the user stays logged in across reloads localStorage.setItem('credential', JSON.stringify(credential))The login flow repeats the same insecure persistence pattern:
typescript const credential = await toWebAuthnCredential({ transport: passkeyTransport, mode: WebAuthnMode.Login, }) localStorage.setItem('credential', JSON.stringify(credential))Technical Analysis
The examples serialize a
P256Credentialobject and place it inlocalStorage. Data inlocalStorageis available to every JavaScript context running under the same origin. It does not receive the confidentiality protections provided by anHttpOnlysession cookie.Consequently, an attacker who obtains same-origin script execution through cross-site scripting, a compromised frontend dependency, malicious analytics code, or another injected script can read and export the serialized credential object. The exact ability to authenticate using the extracted object depends on the SDK representation and authenticator requirements; WebAuthn private key material should ordinarily remain inside the authenticator. Nevertheless, exposing credential identifiers and related authentication state increases the impact of frontend compromise and may facilitate session abuse, correlation, credential-targeting attacks, or replay attempts where the surrounding implementation improperly treats the serialized object as sufficient authentication state.
The parent Skill recognizes this risk in
SKILL.mdby stating thatlocalStorageis for a quick example onl ...[truncated 1686 chars]- Remediation
View remediation
Remediation Suggestions
- Remove all examples that serialize sensitive credential objects into
localStorage. - Keep WebAuthn private key operations within the platform authenticator and persist only the minimum non-secret credential identifier or account metadata required by the application.
- Use a server-managed session represented by a cookie configured with
HttpOnly,Secure, and an appropriateSameSitepolicy. - Require a fresh WebAuthn assertion before sensitive wallet operations instead of treating restored browser data as proof of authentication.
- Apply a restrictive Content Security Policy and Trusted Types where supported to reduce XSS exposure.
- Minimize third-party scripts and audit frontend dependencies that execute in the wallet origin.
- Clear obsolete authentication state on logout, account recovery, credential revocation, and session expiry.
- Make the secure implementation the primary reference example rather than relying solely on a warning in
SKILL.md.
- Remove all examples that serialize sensitive credential objects into
