Skip to content

Permissions reference ​

Path-bearing Bridge endpoints are validated by BridgeCore path-security specs before the handler body runs. Validation may resolve file locations and query the filesystem and media membership; rejected requests do not enter the handler. A path the policy refuses returns PERMISSION_DENIED; a parameter of the wrong shape or type returns INVALID_PARAMS.

Counts are taken from the @security and @pathKey declarations in src/api/schema/*.ts, which generate the path-security specs every registration uses:

LevelSpec countMeaning
Read6Ordinary filesystem read checks
Write1Strict write destinations (config/temp style policy)
MediaRead53Media-context read checks
MediaWrite10Media-context write checks
FileWrite11General file writes (file.*)
Total8176 unique APIs

Six-level model ​

LevelDescriptionValidation summary
NoneNo file-path parameterNo path validation
ReadRead-only filesystem operationsBlocks system protected directories, device paths, and .. traversal
WriteWrite destinations under the strict write policyAllowed only under foobar2000 profile / temp destinations enforced by PathSecurity
MediaReadMedia metadata/content readsRead rules apply to the physical location first; media-library, playlist and watch-folder trust provide a fallback that still checks the resolved target
MediaWriteMedia mutation (tags, lyrics, artwork, counts)Own chain: protected-directory blacklist, then strict write destination, media-library / playlist membership, media-library watch folders, or a sidecar sharing the directory of a trusted audio file. A non-system drive alone does not grant write access
FileWriteGeneral file writes (file.*)Own chain, not a superset of MediaWrite: blacklist, then strict write destination, media-library watch folders, a non-system volume (including a true remote share; loopback shares follow their local target), or media-library / playlist membership — no sidecar step. The watch-folder and non-system-volume steps let file.mkdir and file.write create brand-new paths

Level relationships

  • Standard filesystem channel: None < Read < Write
  • Media channel: None < Read < MediaRead < MediaWrite
  • Independent write channels: Write, MediaWrite, and FileWrite form three separate write channels

FileWrite is broader than MediaWrite

FileWrite permits writes to arbitrary paths on non-system drives, as well as any path inside a media-library watch folder (including on the system drive). It constitutes the widest write channel exposed by the component, intentionally designed for arbitrary file operations via file.* (where imposing media-membership rules would prevent creating new files or folders). Security audits of third-party themes should prioritize reviewing file.* invocations.

Media path resolution ​

MediaRead extracts the physical container from unpack:// or supported archive:// paths, unwrapping nested unpack paths one layer at a time. foobar2000 resolves a file-relative:// physical location before the host checks its device path, directory permissions, mapped drive and UNC rules. Archive entry names are not checked as local directories. Failed resolution still returns PERMISSION_DENIED.

The physical location is used only for authorization. Reading and path echoes retain the original track path, and |subsong:N still selects that track's subsong. Library membership queries retain this index. An authorized container does not imply that every endpoint supports its contents: artwork endpoints' own portable-path restrictions, lyrics sidecar lookup and media streaming's local-file restrictions still follow their individual contracts.

This resolution applies only to MediaRead; other access levels retain their own rules. MediaRead describes parameter authorization, not whether the method has side effects: playback, playlist additions and ReplayGain scanning also use it.

Error response ​

json
{
  "success": false,
  "error": "file.read: path security denied for 'path': Access denied: protected system path",
  "code": "PERMISSION_DENIED"
}

The rejected path is never echoed back. The message names the method, the offending parameter (plus its index for array parameters, as in items[2].destination) and the policy reason, so a caller can tell which argument was refused without the host leaking a filesystem location into a payload a page may forward elsewhere.

json
{
  "success": false,
  "error": "file.read: param 'path' must be a string",
  "code": "INVALID_PARAMS"
}
javascript
const result = await fb2k.invoke('file.read', { path: somePath });
if (result.success === false) {
  if (result.code === 'PERMISSION_DENIED') {
    console.warn('Path rejected by security policy:', result.error);
  } else if (result.code === 'INVALID_PARAMS') {
    console.warn('Parameter rejected before the handler ran:', result.error);
  }
}

API permission matrix ​

Read — filesystem read (6 specs) ​

APIParameterArrayNested key
file.copysource——
file.copyAsyncitemsyessource
file.existspath——
file.getInfopath——
file.listpath——
file.readpath——

Write — strict write destinations (1 spec) ​

APIParameterArrayNested key
http.downloadsaveTo——

MediaRead — media reads (53 specs) ​

APIParameterArrayNested key
artwork.getAvailableArtworkpath——
artwork.getAvailableTypespath——
artwork.getBatchpathsyes—
artwork.getByPathpath——
artwork.getFb2kUrlByPathpath——
artwork.getFb2kUrlByPathBatchitemsyespath
artwork.getFb2kUrlByPathBatchpathsyes—
artwork.getFolderImagesdirectory——
artwork.getForTrackpath——
artwork.getLyricspath——
artwork.getMetadatapath——
audio.analyzeBPMpath——
audio.decodePcmpath——
audio.generateFullWaveformpath——
clipboard.writeFilespathsyes—
discovery.executeContextMenuByPathtrackPath——
jitQueue.enqueueNexturl——
jitQueue.playNowurl——
jitQueue.preloadBatchurlsyes—
jitSession.playlocation——
jitSession.setNextlocation——
library.addToPlaylistpathsyes—
library.getByPathpath——
lyrics.existspath——
lyrics.getpath——
media.getContainerInfopath——
media.getStreamUrlpath——
metadata.probeBatchAsyncpathsyes—
metadata.readpath——
metadata.readBatchpathsyes—
metadata.readByPathpath——
metadata.readRawpath——
playback.playPathpath——
playback.playPathspathsyes—
playcount.getpathsyes—
playcount.getBatchpathsyes—
playlist.addHandleshandlesyespath
playlist.addPathspathsyes—
playlist.addPathsAsyncpathsyes—
playlist.addPathsSequentialpathsyes—
playlist.insertTrackshandlesyespath
playlist.replaceAllAndPlaypathsyes—
queue.addPathspathsyes—
queue.insertNextpathsyes—
rating.getpath——
replaygain.getpathsyes—
replaygain.scanpathsyes—
shell.openWithpath——
shell.showInExplorerpath——
titleformat.evalpath——
titleformat.evalBatchpathsyes—
titleformat.evalFieldspath——
titleformat.evalFieldsBatchpathsyes—

MediaWrite — media mutation (10 specs) ​

APIParameterArrayNested key
lyrics.savepath——
metadata.embedArtworkpath——
metadata.removeEmbeddedArtpath——
metadata.removeFieldpath——
metadata.removeTagpath——
metadata.writepath——
metadata.writeBatchitemsyespath
playcount.setpath——
rating.setpath——
replaygain.clearpathsyes—

Nested array validation

metadata.writeBatch validates each object in items by reading the nested path key.

FileWrite — general file writes (11 specs) ​

APIParameterArrayNested key
file.copydestination——
file.copyAsyncitemsyesdestination
file.deletepath——
file.deleteAsyncpathsyes—
file.mkdirpath——
file.movedestination——
file.movesource——
file.moveAsyncitemsyesdestination
file.moveAsyncitemsyessource
file.renamepath——
file.writepath——

file.copy validates source as Read and destination as FileWrite; file.move validates both endpoints as FileWrite. The asynchronous family follows the same split: file.copyAsync checks every items[].source as Read and every items[].destination as FileWrite, file.moveAsync checks both nested keys as FileWrite, and file.deleteAsync checks every entry of paths as FileWrite. Validation is fail-fast per call: one rejected entry fails the whole batch with PERMISSION_DENIED and no operation is dispatched.

Custom / non-decorator policy ​

These endpoints manage their own policy outside ordinary decorator specs:

APIPolicy notes
shell.execNo executable whitelist; optional cwd still goes through PathSecurity
shell.spawnNo executable whitelist; absolute executable path and cwd are path-checked
console.logLog directory restriction, reserved device names, and .log / .txt extension allowlist

Path security details ​

Common rejections ​

  • Device paths: \\.\... and \\?\...
  • Directory traversal: any path segment that is . or .. (consecutive periods within a file name, such as Bonus Track..flac, are valid path characters)
  • Empty or relative paths (absolute paths required)

Read ​

System-drive protected directories include:

DirectoryReason
C:\\Windows\\OS files
C:\\Program Files\\Installed programs
C:\\Program Files (x86)\\32-bit programs
C:\\ProgramData\\System configuration data

The foobar2000 profile directory is exempt from this list. A portable installation inside C:\Program Files\ can still read and write its own profile, including its template folders.

Outside the protected directories, Read on the system drive allows only the foobar2000 profile, the temporary directory, OneDrive, and the user's Music, Videos, Pictures, Desktop, Documents and Downloads folders.

Non-system drives are generally allowed for portable / NAS media workflows under Read.

Write ​

Only destinations accepted by the strict write policy succeed. In practice this is the foobar2000 profile directory and the system temporary directory.

MediaRead ​

The Read rules run first and the path is accepted as soon as they pass. A non-system-drive path — including a UNC / NAS share — is therefore allowed without any media-library or playlist lookup.

Media-context trust is a fallback, reached only when the Read rules reject the path (in practice, a system-drive path outside the whitelist). Any one of these admits the path:

  • it is addable to the foobar2000 media library, or
  • it resolves to a media library item, or
  • it matches a playlist item. This lookup is served by a membership index that covers every playlist in full, so a genuine match is always found.

MediaWrite ​

MediaWrite does not delegate to the Read or MediaRead entry points; it runs its own chain. After the common rejections, a protected-directory blacklist check always applies, then the first of these to match admits the path:

  • a strict write destination (profile / temp), or
  • a path in media-library / playlist context, or
  • a path under a media-library watch folder, which covers files already on disk but not yet scanned into the library, or
  • a file in the same directory as a trusted context media file, which is how sidecar writes such as .lrc are permitted.

The blacklist is what MediaWrite adds over MediaRead: a protected system directory stays blocked even when the item does appear in a library or playlist.

Being on a non-system drive does not by itself admit a MediaWrite path. The read policy allows non-system drives, but inheriting that on the write side would mean any theme could rewrite arbitrary audio files on D: or E:.

FileWrite ​

FileWrite runs its own chain and is not a superset of MediaWrite. After the common rejections and the protected-directory blacklist, the first of these to match admits the path: a strict write destination (profile / temp), a media-library watch folder (is_path_addable — configuration, not membership, so it admits brand-new paths and UNC folders), a non-system drive addressed by drive letter (UNC excluded), or media-library / playlist context. MediaWrite's sidecar step is absent here.

FileWrite accepts any non-system drive

This is the widest write channel currently exposed; file.delete and file.write accept arbitrary destinations on other drives such as D: or E:. This allowance is maintained to permit file.mkdir and file.write to create new paths on data volumes, which by definition cannot yet exist in a library or playlist and would otherwise be rejected by membership checks alone. Watch folders are different: since is_path_addable checks configuration rather than membership, new paths inside a configured folder are admitted without needing this allowance.

The test applies to the drive letter after canonicalization, not to the one in the path as passed in. If a user directory is redirected onto a non-system drive by a junction or symbolic link (for example C:\Users\<user> → E:\Users\<user>, common on machines whose user profiles have been relocated), its entire subtree is evaluated in its E: form and therefore falls inside this allowance — even though the caller passed a path beginning with C:. The allowance is independent of file extension. When reviewing a theme, do not rely on the literal drive letter; check how the target machine actually redirects these directories.

The counts and the per-level tables on this page are generated from the @security and @pathKey declarations in src/api/schema/*.ts.