Skip to content

fix(security): restrict temp file permissions and validate memory_limit#368

Merged
xe-nvdk merged 3 commits into
mainfrom
release/26.04.1
Apr 1, 2026
Merged

fix(security): restrict temp file permissions and validate memory_limit#368
xe-nvdk merged 3 commits into
mainfrom
release/26.04.1

Conversation

@xe-nvdk
Copy link
Copy Markdown
Member

@xe-nvdk xe-nvdk commented Apr 1, 2026

Summary

Test plan

  • go build ./... passes
  • go test ./internal/backup/... ./internal/api/... ./internal/database/... ./internal/compaction/... all pass
  • Verify temp files created during restore/delete/profiling are 0600 on disk
  • Verify invalid memory_limit values (e.g. "1GB; DROP TABLE") are rejected at startup

- chmod 0600 on CreateTemp files in restore, delete, and duckdb profiling
  to prevent world-readable parquet data and profile output (closes #362)
- validate memory_limit with regex before SQL interpolation in compaction
  subprocess to prevent injection via config (closes #363)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds explicit file permission settings for temporary files and introduces regex-based validation for DuckDB memory limits. The review feedback points out that the os.Chmod calls are redundant as os.CreateTemp already defaults to 0600 permissions. Additionally, the reviewer suggests centralizing the memory limit validation logic to ensure consistency and prevent potential SQL injection in other database configurations.

Comment thread internal/api/delete.go Outdated
Comment on lines +626 to +630
if err := os.Chmod(tempFile.Name(), 0600); err != nil {
tempFile.Close()
os.Remove(tempFile.Name())
return 0, fmt.Errorf("failed to secure temp file: %w", err)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The call to os.Chmod is redundant here. In Go, os.CreateTemp already creates files with 0600 permissions (readable and writable only by the owner) by default. Adding an explicit Chmod adds unnecessary complexity and an extra error handling path for a condition that is already guaranteed by the standard library.

Comment thread internal/backup/restore.go Outdated
Comment on lines +149 to +153
if err := os.Chmod(tmpFile.Name(), 0600); err != nil {
tmpFile.Close()
os.Remove(tmpFile.Name())
return 0, fmt.Errorf("failed to secure temp file: %w", err)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This os.Chmod call is redundant. Go's os.CreateTemp implementation ensures that the temporary file is created with 0600 permissions. You can safely remove this block to simplify the code and avoid unnecessary system calls.

Comment thread internal/compaction/subprocess.go Outdated
Comment on lines +96 to +98
if !memLimitRe.MatchString(config.MemoryLimit) {
return nil, fmt.Errorf("invalid memory_limit value: %q", config.MemoryLimit)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The addition of memory_limit validation is a significant security improvement to prevent SQL injection. However, to ensure consistency and prevent similar vulnerabilities elsewhere, consider centralizing this regex (e.g., in a shared utility package) and applying the same validation to the main database configuration in internal/database/duckdb.go, which currently interpolates the MemoryLimit value without similar validation.

Comment thread internal/database/duckdb.go Outdated
Comment on lines +563 to +573
if err := os.Chmod(tmpFile.Name(), 0600); err != nil {
tmpFile.Close()
os.Remove(tmpFile.Name())
// Fall back to regular query
rows, err := conn.QueryContext(ctx, query)
if err != nil {
conn.Close()
return nil, nil, nil, err
}
return rows, conn, nil, nil
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block is redundant and introduces significant code duplication. os.CreateTemp already ensures 0600 permissions. Furthermore, the error handling logic here (lines 564-572) is a duplicate of the fallback logic already implemented for the os.CreateTemp failure above (lines 556-561). Removing this block improves maintainability without compromising security.

Centralize memory_limit validation in config.Load() with a regex guard
instead of at each call site. os.CreateTemp already creates 0600 files
so chmod calls were redundant and have been removed.

Addresses Gemini review feedback on #368.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@xe-nvdk
Copy link
Copy Markdown
Member Author

xe-nvdk commented Apr 1, 2026

Addressed Gemini feedback:

  • Removed redundant chmod calls — Go stdlib docs confirm CreateTemp creates files with 0600 permissions, so explicit chmod was unnecessary.
  • Centralized memory_limit validation in config.Load() (internal/config/config.go) instead of at each call site. Invalid values now fail fast at startup before reaching duckdb.go or compaction/subprocess.go.

Net: +7 -27 lines.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@xe-nvdk xe-nvdk merged commit e6fe712 into main Apr 1, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant