Imports
Import shared instrument collections from external .ins files so songs stay short and libraries stay reusable.
Syntax
import "local:path/to/instruments.ins" # CLI / desktop only
import "github:user/repo/branch/file.ins" # CLI, desktop, and browser
import "https://example.com/path/file.ins" # CLI, desktop, and browser
- Local imports require the
local:prefix and need filesystem access (CLI/desktop). They are blocked in the browser for security. - Remote imports use
github:orhttps:and work in the BeatBax CLI, BeatBax Desktop, and the BeatBax web-lite client. - Paths for
local:are relative to the song file (e.g.local:lib/common.insorlocal:../shared/drums.ins), with a fallback search from the current working directory. - Recursive imports are allowed; cycles are detected automatically.
- Merging is last-wins: local
instdefinitions in the song override imported ones with the same name.
Example songs in the toolchain repo: songs/features/local_import_example.bax, songs/features/remote_import_example.bax.
Import security
BeatBax validates import paths to prevent path traversal and unauthorized file access.
As of February 2026, BeatBax requires explicit import prefixes:
local:for local filesystem imports (CLI/desktop only)https://orgithub:for remote imports (CLI, desktop, and browser)- Browser environments block all local imports for security
1. Import prefix requirement
All imports must use explicit prefixes:
// ✅ VALID - Local file import (CLI only)
import "local:lib/common.ins"
import "local:instruments/drums.ins"
// ✅ VALID - Remote imports (CLI and browser)
import "https://raw.githubusercontent.com/user/repo/main/file.ins"
import "github:user/repo/main/file.ins"
// ❌ REJECTED - Missing prefix
import "lib/common.ins"
import "instruments/drums.ins"
This requirement ensures:
- Import intentions are explicit and clear
- Prevents accidental file system access
- Enables browser security (see below)
- Makes code more auditable and secure
2. Browser security
When running in a browser environment, BeatBax automatically blocks local file imports:
// In browser - BLOCKED with security error
import "local:lib/common.ins"
// Error: Local imports are not supported in the browser for security reasons.
// Import "local:lib/common.ins" cannot be loaded.
// Use remote imports (https:// or github:) instead, or run in CLI for local file access.
// In browser - ALLOWED
import "https://example.com/instruments/drums.ins"
import "github:kadraman/beatbax-instruments/main/melodic.ins"
Browser Detection:
The engine uses typeof window !== 'undefined' to detect browser contexts and enforce this restriction automatically. This prevents browser-based attacks that could attempt to read local file system contents.
CLI Warnings:
When using --browser flag with songs containing local imports, the CLI displays a warning:
⚠️ Warning: This song contains N local file import(s) which will be blocked by browser security.
The browser will display an error when attempting to load this song.
To play this song in the browser, replace local imports with remote imports (https:// or github:).
3. Path Traversal Prevention
Import paths containing .. as a path segment are rejected to prevent directory traversal attacks:
# ❌ REJECTED - path traversal with .. segments
import "local:../../../etc/passwd"
import "local:lib/../../secrets/keys.txt"
import "local:subdir/../../../outside/file.ins"
import "local:lib/.."
# ✅ ALLOWED - filenames containing ".." as part of the name
import "local:lib/drums..backup.ins"
import "local:lib/file..old.ins"
import "local:lib/my..version2.ins"
The validation uses a path segment check (regex: /(^|\/)\.\.($|\/)/) which:
- Blocks
.when preceded by/or start-of-string AND followed by/or end-of-string - Allows
..as part of a filename (e.g.,drums..backup.ins)
This prevents path traversal attacks while allowing legitimate filenames that happen to contain two consecutive dots.
4. Absolute Path Restriction
By default, absolute paths are not allowed in import statements:
// ❌ REJECTED by default - Unix absolute path
import "/etc/passwd"
import "/var/www/data.ins"
// ❌ REJECTED by default - Windows absolute path
import "C:/Windows/System32/config/sam"
import "D:\\secrets\\passwords.txt"
This ensures that imports are always relative to the project structure.
5. Allowed Directory Validation
Even after passing initial validation, the resolved path must be within one of the allowed directories:
- The directory containing the importing file (base directory)
- Any configured search paths
If the resolved path falls outside these directories, the import is rejected:
// Example: importing from /project/main.bax
import "lib/common.ins" // ✅ resolves to /project/lib/common.ins (allowed)
Configuration
Default Behavior
By default, only relative imports within the project directory and configured search paths are allowed:
import { resolveImports } from '@beatbax/engine';
const resolved = resolveImports(ast, {
baseFilePath: '/project/songs/main.bax',
searchPaths: ['/project/lib'],
// absolutePaths are NOT allowed by default
});
Allowing Absolute Paths
For advanced use cases (e.g., shared instrument libraries in system directories), you can enable absolute paths:
const resolved = resolveImports(ast, {
baseFilePath: '/project/main.bax',
searchPaths: ['/usr/share/beatbax/instruments'],
allowAbsolutePaths: true, // Enable absolute paths
});
Important: Even with allowAbsolutePaths: true, path traversal using .. is still rejected. Absolute paths must still resolve to an allowed directory (search paths).
Valid Import Patterns
Local Imports (CLI Only)
// Import from same directory
import "local:common.ins"
// Import from subdirectory
import "local:lib/drums.ins"
import "local:instruments/bass.ins"
// Import from nested subdirectories
import "local:lib/chiptune/gameboy/pulse.ins"
Remote Imports (CLI and Browser)
// HTTPS URL
import "https://raw.githubusercontent.com/user/repo/main/instruments.ins"
// GitHub shorthand
import "github:user/repo/main/instruments.ins"
Absolute Imports (When Enabled)
// With allowAbsolutePaths: true and appropriate searchPaths
import "/usr/share/beatbax/instruments/standard.ins"
import "C:/BeatBax/Library/drums.ins"
Error Messages
When security validation fails, BeatBax provides clear error messages:
Missing Import Prefix
Error: Invalid import path "lib/common.ins": local file imports must use "local:" prefix.
Use "local:lib/common.ins" instead.
Remote imports should use "https://" or "github:" prefix.
Browser Security Violation
Error: Local imports are not supported in the browser for security reasons.
Import "local:lib/common.ins" cannot be loaded.
Use remote imports (https:// or github:) instead, or run in CLI for local file access.
Path Traversal Detected
Error: Invalid import path "local:../../../etc/passwd":
path traversal using ".." is not allowed for security reasons
Absolute Path Not Allowed
Error: Invalid import path "local:/etc/passwd":
absolute paths are not allowed for security reasons
Outside Allowed Directories
Error: Security violation: import path "local:../../outside/file.ins"
resolves to "/outside/file.ins" which is outside the allowed directories
Best Practices
For Users
- Use
local:prefix for all local file imports in CLI - Use remote imports (
https://orgithub:) when sharing or for browser playback - Organize imports in a dedicated directory (e.g.,
lib/orinstruments/) - Never trust
.baxfiles from untrusted sources without inspection - Configure search paths instead of using absolute paths when possible
- Test in browser to ensure remote imports work correctly
For Tool Developers
- Never enable
allowAbsolutePathswithout explicit user consent - Validate and sanitize any user-provided search paths
- Log security rejections for audit purposes
- Consider sandboxing when executing untrusted
.baxfiles - Use virtual file systems for testing to avoid real file system access
Implementation Details
The security validation happens in two stages:
-
Pre-resolution validation - Checks import path syntax before resolution
- Rejects
..segments - Rejects absolute paths (unless allowed)
- Rejects
-
Post-resolution validation - Verifies resolved path is within allowed directories
- Uses normalized paths for comparison
- Checks against base directory and all search paths
This two-stage approach provides defense in depth, catching both obvious attacks and subtle bypasses.
Testing
The security features are covered by comprehensive tests in packages/engine/tests/resolver.imports.test.ts:
npm test -- resolver.imports.test
Test cases include:
- Path traversal attempts with various
..patterns - Unix and Windows absolute path formats
- Valid relative paths in subdirectories
- Absolute paths with
allowAbsolutePathsenabled - Path traversal rejection even with
allowAbsolutePaths - Resolved path validation against allowed directories
Security Considerations
Not a Complete Sandbox
These measures protect against basic path traversal attacks but do not provide complete sandboxing:
- Symlink attacks are not prevented (symlinks are followed by the file system)
- Time-of-check-time-of-use (TOCTOU) races could occur in theory
- Resource exhaustion (import bombs) is not prevented
- Malicious .bax code execution is out of scope (BeatBax is a data format, not a programming language with arbitrary code execution)
When Additional Security Is Required
For high-security environments or running untrusted code:
- Use a virtual file system or chroot jail
- Run BeatBax in a container or VM
- Implement resource limits (max file size, max imports, max recursion depth)
- Audit all imports before execution
- Use signed/verified instrument libraries only
Migration Guide
Breaking Change (February 2026): All local imports now require the local: prefix.
# Before (no longer accepted)
import "lib/common.ins"
import "instruments/drums.ins"
# After (required)
import "local:lib/common.ins"
import "local:instruments/drums.ins"
# Or use remote imports for browser compatibility
import "github:kadraman/beatbax-instruments/main/common.ins"
Automatic Migration:
Update all import statements in your .bax and .ins files by adding the local: prefix to file paths that don't start with https:// or github:.
Related documentation
- Remote Imports —
https://andgithub:imports - Instruments reference
- Instruments tutorial
Path Traversal Guard — Validation Examples
The engine blocks .. when used as a path segment for directory traversal, while allowing filenames that contain .. as a substring.
Regex: /(^|\/)\.\.($|\/)/
Allowed (`.." inside a filename, not a segment)
local:lib/drums..backup.ins ✅
local:lib/file..old.ins ✅
local:lib/my..version2.ins ✅
local:.hidden..file.ins ✅
local:lib/.hidden.ins ✅ (hidden file, single dot)
local:lib/file.v2.ins ✅
local:...special.ins ✅ (three dots — not two)
Rejected (.. as a path component)
local:../parent/file.ins ❌
local:../../grandparent/file.ins ❌
local:lib/../sibling/file.ins ❌
local:lib/.. ❌
local:./lib/../../../etc/passwd ❌
Implementation: packages/engine/src/song/importResolver.ts
Tests: packages/engine/tests/resolver.imports.path-segment-validation.test.ts