Tencent/WeKnora · error

sandbox: install file path %q is outside %s

Error message

sandbox: install file path %q is outside %s

What it means

Returned by WriteSessionFile when the requested install/maintenance filePath escapes the tenant skills image root. This write path is deliberately restricted to that root (ordinary attachments must go through WriteSessionFile's /workspace/input-guarded sibling), so an out-of-root path — including traversal attempts — is rejected before touching the sandbox.

Source

Thrown at internal/sandbox/session_manager.go:650

	return m.client.ReadFile(ctx, handle, filePath)
}

// WriteSessionFile writes an install/maintenance file into the session's live
// sandbox. It is deliberately narrower than a general remote write: only the
// tenant skills image root is accepted, because ordinary attachments must keep
// using WriteSessionInputFile and its /workspace/input guard.
func (m *SessionBoundManager) WriteSessionFile(
	ctx context.Context, sessionID, filePath string, content []byte,
) error {
	if err := m.requireRemoteBackend(); err != nil {
		return err
	}
	if strings.TrimSpace(sessionID) == "" {
		return errors.New("sandbox: session ID required for file staging")
	}
	clean := path.Clean(strings.TrimSpace(filePath))
	if clean != SkillsImageRoot && !strings.HasPrefix(clean, SkillsImageRoot+"/") {
		return fmt.Errorf("sandbox: install file path %q is outside %s", filePath, SkillsImageRoot)
	}
	handle, err := m.resolveSession(ctx, sessionID)
	if err != nil {
		return err
	}
	// resetSkillDir already created this folder with mkdir -p. Cube's MakeDir
	// then reports the existing directory as an error; ignoreExistingDir keeps
	// that from aborting the seed of SKILL.md.
	if err := ignoreExistingDir(m.client.MakeDir(ctx, handle, path.Dir(clean))); err != nil {
		return fmt.Errorf("sandbox: create install directory: %w", err)
	}
	if err := m.client.WriteFile(ctx, handle, clean, content); err != nil {
		return fmt.Errorf("sandbox: write install file %s: %w", clean, err)
	}
	return nil
}

// ShellExecOptions carries per-call shell execution knobs. The install-only

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Place install files under the tenant skills image root and use root-relative paths
  2. Route general file uploads through WriteSessionInputFile instead
  3. Reject or sanitize caller-supplied paths before calling WriteSessionFile
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at internal/sandbox/session_manager.go:650 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/221fe7093580923d. Report an issue: GitHub.