moonD4rk/HackBrowserData · error

abe: read Local State: %w

Error message

abe: read Local State: %w

What it means

loadEncryptedKey reads Chrome's 'Local State' JSON file to extract os_crypt.app_bound_encrypted_key. This error wraps an os.ReadFile failure, meaning the Local State file could not be opened or read (missing file, permission denied, locked, etc.).

Source

Thrown at masterkey/abe_windows.go:76

	inj := &injector.Reflective{}
	key, err := inj.Inject(exePath, pl, env)
	if err != nil {
		return nil, fmt.Errorf("abe: inject into %s: %w", exePath, err)
	}
	if len(key) != 32 {
		return nil, fmt.Errorf("abe: unexpected key length %d (want 32)", len(key))
	}
	log.Infof("abe: retrieved %s master key via reflective injection", browserKey)
	return key, nil
}

func loadEncryptedKey(localStatePath string) ([]byte, error) {
	if localStatePath == "" {
		return nil, errNoABEKey
	}
	data, err := os.ReadFile(localStatePath)
	if err != nil {
		return nil, fmt.Errorf("abe: read Local State: %w", err)
	}

	raw := gjson.GetBytes(data, "os_crypt.app_bound_encrypted_key")
	if !raw.Exists() {
		return nil, errNoABEKey
	}

	decoded, err := base64.StdEncoding.DecodeString(raw.String())
	if err != nil {
		return nil, fmt.Errorf("abe: base64 decode: %w", err)
	}
	if len(decoded) <= len(appbPrefix) {
		return nil, fmt.Errorf("abe: encrypted key too short: %d bytes", len(decoded))
	}
	for i, b := range appbPrefix {
		if decoded[i] != b {
			return nil, fmt.Errorf("abe: unexpected prefix: got %q, want %q",
				decoded[:len(appbPrefix)], appbPrefix)

View on GitHub (pinned to 0503d04d7a)

Solutions

  1. Verify localStatePath points at <user data dir>/Local State for the correct profile and user.
  2. Check file permissions / run with the rights needed to read the target profile.
  3. Close Chrome (or copy the file first) if the file is locked by a running browser instance.
  4. If the file genuinely doesn't exist, treat this as errNoABEKey and fall back to a non-ABE decryption path instead of failing.

Example fix

// before
key, err := RetrieveKey(exePath, localStatePath)
// after - pre-check the file before attempting ABE
if _, err := os.Stat(localStatePath); err != nil {
	log.Warnf("Local State not readable at %s: %v; skipping ABE", localStatePath, err)
	return fallbackDecrypt()
}
key, err := RetrieveKey(exePath, localStatePath)
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(localStatePath)
if err != nil {
	return fmt.Errorf("Local State not accessible at %s: %w", localStatePath, err)
}
if info.IsDir() {
	return fmt.Errorf("%s is a directory, expected the Local State file", localStatePath)
}

Try / catch

key, err := RetrieveKey(exePath, localStatePath)
if err != nil {
	if errors.Is(err, os.ErrNotExist) || errors.Is(err, os.ErrPermission) {
		log.Warnf("cannot read Local State: %v; skipping ABE", err)
		return fallbackDecrypt()
	}
	return err
}

Prevention

When it happens

Trigger: Calling RetrieveKey (which calls loadEncryptedKey) with a localStatePath pointing to a nonexistent, unreadable, or locked 'Local State' file, or when Chrome is running and holds an exclusive lock on the profile.

Common situations: Wrong profile path passed in (e.g. pointing at the wrong user data dir); running without permissions to read another user's profile; Chrome running and file locked on Windows; empty path (though empty path short-circuits to errNoABEKey first).

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/21d373d42428396f. Report an issue: GitHub.