moonD4rk/HackBrowserData · error
read Local State: %w
Error message
read Local State: %w
What it means
On Windows, DPAPIRetriever reads Chrome's 'Local State' JSON file (in the profile's User Data dir) to obtain os_crypt.encrypted_key. os.ReadFile failed, so the path is wrong, the file is missing, or it cannot be opened — no V10 key can be unwrapped without it.
Source
Thrown at masterkey/retriever_windows.go:21
package masterkey
import (
"encoding/base64"
"fmt"
"os"
"github.com/tidwall/gjson"
"github.com/moond4rk/hackbrowserdata/crypto"
)
// DPAPIRetriever unwraps Chrome's Local State os_crypt.encrypted_key via Windows DPAPI.
type DPAPIRetriever struct{}
func (r *DPAPIRetriever) RetrieveKey(hints Hints) ([]byte, error) {
data, err := os.ReadFile(hints.LocalStatePath)
if err != nil {
return nil, fmt.Errorf("read Local State: %w", err)
}
encryptedKey := gjson.GetBytes(data, "os_crypt.encrypted_key")
if !encryptedKey.Exists() {
return nil, fmt.Errorf("os_crypt.encrypted_key not found in Local State")
}
keyBytes, err := base64.StdEncoding.DecodeString(encryptedKey.String())
if err != nil {
return nil, fmt.Errorf("base64 decode encrypted_key: %w", err)
}
const dpapiPrefix = "DPAPI"
if len(keyBytes) <= len(dpapiPrefix) {
return nil, fmt.Errorf("encrypted_key too short: %d bytes", len(keyBytes))
}
if string(keyBytes[:len(dpapiPrefix)]) != dpapiPrefix {
return nil, fmt.Errorf("encrypted_key unexpected prefix: got %q, want %q", keyBytes[:len(dpapiPrefix)], dpapiPrefix)View on GitHub (pinned to 0503d04d7a)
Solutions
- Verify the path exists: the file lives at %LOCALAPPDATA%\Google\Chrome\User Data\Local State (adjust per browser)
- Check hints.LocalStatePath is actually pointing to the 'User Data' root's Local State, not a profile subfolder (Default/…)
- Ensure the process runs as the same user whose profile is being read, or as admin, with read access to the directory
- Close Chrome or copy the file if it is locked, then retry
Example fix
// before
retriever.RetrieveKey(masterkey.Hints{LocalStatePath: "C:\\Program Files\\Google\\Chrome\\Local State"})
// after
retriever.RetrieveKey(masterkey.Hints{LocalStatePath: filepath.Join(os.Getenv("LOCALAPPDATA"), "Google", "Chrome", "User Data", "Local State")}) Defensive patterns
Strategy: validation
Validate before calling
lsPath := filepath.Join(os.Getenv("LOCALAPPDATA"), "Google", "Chrome", "User Data", "Local State")
if fi, err := os.Stat(lsPath); err != nil || fi.IsDir() {
// Local State missing — fix hints.LocalStatePath or skip v10 tier
} Try / catch
key, err := dpapiRetriever.RetrieveKey(hints)
if err != nil {
var perr *fs.PathError
if errors.As(err, &perr) && strings.Contains(err.Error(), "read Local State") {
log.Warnf("Local State unreadable at %s: %v", hints.LocalStatePath, perr)
}
} Prevention
- Build LocalStatePath from %LOCALAPPDATA% per browser instead of hardcoding paths
- Point at the User Data root's 'Local State', never a Default/ subfolder file
- Run as the profile's owning user (or elevated) when reading other profiles
- Account for custom --user-data-dir installs and Chromium forks with different roots
When it happens
Trigger: RetrieveKey with hints.LocalStatePath pointing to a nonexistent/locked file: browser not installed at the expected location, wrong profile-dir hint, file held open exclusively, or running without read access to another user's profile.
Common situations: Custom Chrome install dir or non-default --user-data-dir; Chrome running and locking files (rare); the tool run as a different user without permissions on %LOCALAPPDATA%; typo'd path passed programmatically.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- os_crypt.encrypted_key not found in Local State
- DPAPI not supported on this platform
- abe: Local State has no app_bound_encrypted_key
- abe: read Local State: %w
- base64 decode encrypted_key: %w
AI-assisted analysis of moonD4rk/HackBrowserData@0503d04d7a (2026-09-06).
Data as JSON: /api/errors/21ca0fcd2db5deee.
Report an issue: GitHub.