cloudflare/cloudflared · error

create token security descriptor: %w

Error message

create token security descriptor: %w

What it means

createTokenFile builds the access-token file used by the installed Windows service and first converts a hard-coded SDDL string ('O:BAD:P(A;;FA;;;BA)(A;;FA;;;SY)', granting file access only to Administrators and SYSTEM) into a SECURITY_DESCRIPTOR. windows.SecurityDescriptorFromString fails if the SDDL string cannot be parsed. With the current constant this is practically unreachable, but any malformed SDDL input surfaces here wrapped with this message.

Source

Thrown at cmd/cloudflared/windows_service.go:144

	// - O:BA         -> Set the owner to the builtin administrators group (BA)
	// - D:           -> Start of discretionary access control list describing access rights
	// - P            -> Set the SE_DACL_PROTECTED flag, which prevents the file from
	//                   inheriting the (usually permissive) ACEs from its parent directory
	// - (A;;FA;;;BA) -> ACE #1: Allow (A) Full access (FA) to the Builtin Administrators group (BA)
	// - (A;;FA;;;SY) -> ACE #2: Ditto but for the Local System user (SY)
	//
	// Relevant Docs:
	//
	// - SecurityDescriptor string as a whole:
	//     https://learn.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format
	// - SID Strings such as BA/SY
	//     https://learn.microsoft.com/en-us/windows/win32/secauthz/sid-strings
	// - ACE Strings such as (A;;FA;;BA)
	//     https://learn.microsoft.com/en-us/windows/win32/secauthz/ace-strings
	const sdString = "O:BAD:P(A;;FA;;;BA)(A;;FA;;;SY)"
	sd, err := windows.SecurityDescriptorFromString(sdString)
	if err != nil {
		return fmt.Errorf("create token security descriptor: %w", err)
	}

	pathRaw, err := windows.UTF16PtrFromString(path)
	if err != nil {
		return fmt.Errorf("convert path to UTF-16: %w", err)
	}

	f, err := windows.CreateFile(
		pathRaw,
		windows.GENERIC_WRITE,
		0,
		&windows.SecurityAttributes{
			Length:             uint32(unsafe.Sizeof(windows.SecurityAttributes{})),
			SecurityDescriptor: sd,
			InheritHandle:      0,
		},
		windows.CREATE_ALWAYS, // Will truncate the file if it exists
		windows.FILE_ATTRIBUTE_NORMAL,

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Do not edit the sdString constant unless you validate the SDDL with a Windows tool first
  2. Verify the string parses with PowerShell: ConvertFrom-SddlString 'O:BAD:P(A;;FA;;;BA)(A;;FA;;;SY)'
  3. Rebuild cloudflared from a clean checkout to rule out a tampered source constant
  4. Run `cloudflared service install` on a stock build and file an issue if it still fails

Example fix

// before
const sdString = "O:BAD:P(A;;FA;;;BA)(A;;FA;;;SY"
sd, err := windows.SecurityDescriptorFromString(sdString)
// after
const sdString = "O:BAD:P(A;;FA;;;BA)(A;;FA;;;SY)" // balanced parens, valid ACEs
sd, err := windows.SecurityDescriptorFromString(sdString)
if err != nil {
	return fmt.Errorf("create token security descriptor: %w", err)
}
Defensive patterns

Strategy: try-catch

Try / catch

// caller of service install
if err := installWindowsService(ctx); err != nil {
	var sdErr error
	if errors.Unwrap(err) != nil && strings.Contains(err.Error(), "security descriptor") {
		sdErr = err // SDDL parse issue: report build/version and file a bug
	}
	return err
}

Prevention

When it happens

Trigger: windows.SecurityDescriptorFromString returns a Win32 error for the sdString constant — a parse failure of the security descriptor string.

Common situations: Modifying the hard-coded SDDL string and introducing a typo or an invalid SID/ACE; running on a Windows build whose SDDL parser rejects a component; corrupted golang.org/x/sys/windows build.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/8f38a0b437115e27. Report an issue: GitHub.