Wei-Shaw/sub2api · error
ChatGPT DeviceCheck returned a malformed attestation
Error message
ChatGPT DeviceCheck returned a malformed attestation
What it means
After the DeviceCheck subprocess succeeds, its stdout must be a JSON token header between 20 bytes and 16 KiB. If stdout is too short, too long, empty, or not valid JSON, the attestation is deemed malformed and rejected. This guards the downstream Live protocol from forwarding garbage tokens.
Source
Thrown at backend/internal/platform/liveattestation/attestation_darwin.go:136
var stderr bytes.Buffer
command.Stdout = &stdout
command.Stderr = &stderr
if err := command.Run(); err != nil {
if errors.Is(runCtx.Err(), context.DeadlineExceeded) {
return "", errors.New("ChatGPT DeviceCheck token generation timed out")
}
reason := strings.TrimSpace(stderr.String())
if len(reason) > 240 {
reason = reason[:240]
}
if reason == "" {
reason = err.Error()
}
return "", fmt.Errorf("ChatGPT DeviceCheck token generation failed: %s", reason)
}
header := strings.TrimSpace(stdout.String())
if len(header) < 20 || len(header) > 16*1024 || !json.Valid([]byte(header)) {
return "", errors.New("ChatGPT DeviceCheck returned a malformed attestation")
}
return header, nil
}
func (p *darwinProvider) findApplication() (string, error) {
for _, appPath := range p.appPaths {
info, err := os.Stat(appPath)
if err == nil && info.IsDir() {
return appPath, nil
}
}
return "", ErrChatGPTAppMissing
}
func readBundleIdentifier(ctx context.Context, appPath string) (string, error) {
infoPlist := filepath.Join(appPath, "Contents", "Info.plist")
output, err := exec.CommandContext(
ctx,View on GitHub (pinned to 073e92d171)
Solutions
- Update (or pin) the official ChatGPT app to a version known compatible with Sub2API's attestation shim.
- Run the subprocess manually with the same env (SUB2API_DEVICECHECK_MODULE, SUB2API_ATTESTATION_BUNDLE_ID, SUB2API_ATTESTATION_SIGNALS) and inspect stdout.
- Ensure nothing (wrapper scripts, node --print banners, NVM shims) appends to stdout.
- Report to Sub2API if a ChatGPT app update changed the output shape — the parser needs updating.
Defensive patterns
Strategy: try-catch
Try / catch
if err != nil {
if strings.Contains(err.Error(), "malformed attestation") {
// almost always a ChatGPT app version change: check app version vs known-good list
return appVersionError("update or pin the ChatGPT app bundle")
}
return err
} Prevention
- Pin/verify the ChatGPT app version on attestation hosts
- Run the subprocess manually when triaging (documented SUB2API_* env vars)
- Alert on this error to catch app-update breakage early
When it happens
Trigger: The bundled node process exits 0 but prints a non-JSON banner, an error message, extra logging, or nothing; stdout pollution from the runtime; or a truncated buffer due to the process being killed mid-write (but with a non-deadline error).
Common situations: ChatGPT app updated and its devicecheck.node contract changed (extra output, different format); environment variables leaking extra stdout; locale-specific messages printed by node; module returning an HTML error string instead of JSON.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- ChatGPT DeviceCheck token generation timed out
- live attestation is only supported when Sub2API runs on macO
- live attestation currently requires Apple Silicon; Intel mac
- api_error
- invalid_request_error
AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15).
Data as JSON: /api/errors/656e9800982bcfc5.
Report an issue: GitHub.