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

  1. Verify the path exists: the file lives at %LOCALAPPDATA%\Google\Chrome\User Data\Local State (adjust per browser)
  2. Check hints.LocalStatePath is actually pointing to the 'User Data' root's Local State, not a profile subfolder (Default/…)
  3. Ensure the process runs as the same user whose profile is being read, or as admin, with read access to the directory
  4. 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

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


AI-assisted analysis of moonD4rk/HackBrowserData@0503d04d7a (2026-09-06). Data as JSON: /api/errors/21ca0fcd2db5deee. Report an issue: GitHub.