larksuite/cli · error

exec provider security audit failed: %w

Error message

exec provider security audit failed: %w

What it means

prepareExecRun runs AssertSecurePath to audit the exec provider's command path (ownership, permissions, symlink policy, trusted dirs). When that audit fails, the error is wrapped with this message and returned, refusing to execute an untrusted binary. This protects against running a command that could be tampered with by another user.

Source

Thrown at internal/binding/secret_resolve_exec.go:81

// prepareExecRun audits the command path, marshals the JSON request,
// assembles the minimal child env, and resolves timeout / output limits.
// Never spawns a process — the returned execRun is pure data.
func prepareExecRun(ref *SecretRef, providerName string, pc *ProviderConfig, getenv func(string) string) (*execRun, error) {
	if pc.Command == "" {
		return nil, fmt.Errorf("exec provider command is empty")
	}

	securePath, err := AssertSecurePath(AuditParams{
		TargetPath:            pc.Command,
		Label:                 "exec provider command",
		TrustedDirs:           pc.TrustedDirs,
		AllowInsecurePath:     pc.AllowInsecurePath,
		AllowReadableByOthers: true, // exec commands are typically 755
		AllowSymlinkPath:      pc.AllowSymlinkCommand,
	})
	if err != nil {
		return nil, fmt.Errorf("exec provider security audit failed: %w", err)
	}

	reqJSON, err := marshalExecRequest(ref, providerName)
	if err != nil {
		return nil, err
	}

	timeoutMs, maxOut := effectiveExecLimits(pc)
	return &execRun{
		Path:    securePath,
		Args:    pc.Args,
		Env:     buildExecEnv(pc, getenv),
		Request: reqJSON,
		Timeout: time.Duration(timeoutMs) * time.Millisecond,
		MaxOut:  maxOut,
	}, nil
}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Inspect the wrapped cause (%w) for the exact path violation and fix the file permissions/ownership (e.g. chmod 755, chown to the running user)
  2. Move the command into a directory listed in the provider's trusted-dirs config, or add the command's directory to trusted-dirs
  3. If the command is intentionally a symlink, set allow-symlink-command (AllowSymlinkCommand) to true in the provider config
  4. Verify the command path exists at runtime — a stale path also fails the audit

Example fix

# before (script world-writable)
ls -l /tmp/resolver.sh  # -rwxrwxrwx

# after
chmod 755 /opt/resolver.sh
# config
command: /opt/resolver.sh
trusted-dirs: ["/opt"]
Defensive patterns

Strategy: validation

Validate before calling

// pre-check the command path like the audit does
info, err := os.Stat(p.Command)
if err != nil { return fmt.Errorf("command %s not found", p.Command) }
if info.Mode()&0o022 != 0 {
    return fmt.Errorf("command %s must not be group/other-writable (chmod 755)", p.Command)
}
for _, d := range trustedDirs {
    if strings.HasPrefix(p.Command, d+string(os.PathSeparator)) { return nil }
}
return fmt.Errorf("command %s is outside trusted-dirs", p.Command)

Try / catch

secret, err := resolveSecretRef(ctx, ref)
if err != nil {
    var auditErr *SecurityAuditError
    if errors.As(err, &auditErr) { // or match on the wrapped cause
        log.Fatalf("fix exec command path: %v (chmod/chown, move into trusted-dirs, or allow symlink)", auditErr)
    }
    return err
}

Prevention

When it happens

Trigger: resolveExecRef -> prepareExecRun calls AssertSecurePath and the command path fails the audit: it lives outside TrustedDirs, is writable by others/group when it shouldn't be, is a symlink when AllowSymlinkCommand is false, is world-readable-insecure, or the path doesn't exist.

Common situations: Placing the resolver script in a world-writable directory like /tmp or a shared mount; the command is a symlink into a dev directory; the binary's permissions were loosened (e.g. 777 after chmod mishap); running on a machine where the trusted-dirs config doesn't include the install location; CI checkout makes the script writable by the CI user only but the audit expects stricter ownership.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/5069cc749f42403b. Report an issue: GitHub.