Skip to content

Latest commit

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

secrets-fuse - Secure secrets from filesystem-based credential stores

A FUSE filesystem that exposes secrets from 1Password as virtual files.

Features:

  • Command allowlists - restrict which processes can read each secret
  • Read limits - secrets can self-destruct after N reads
  • Write-back support - update secrets directly through the filesystem

Note

This is a prototype and it is currently limited in the security it provides. While it is still better than a simple filesystem based secret, it is possible to bypass the allowlisting mechanism with a well-timed TOCTOU "swap" attack. Currently looking at improving the security model using fanotify & eBPF for Linux, and ESF for Darwin.

Prerequisites

Enable 1Password Desktop Integration

  1. Open and unlock the 1Password app
  2. Select your account or collection at the top of the sidebar
  3. Navigate to Settings > Developer
  4. Under "Integrate with the 1Password SDKs", select Integrate with other apps
  5. (Optional) For biometric unlock, go to Settings > Security and enable Unlock using Touch ID (macOS) or Windows Hello (Windows)

See 1Password SDK documentation for more details.

Installation

go install github.com/evict/secrets-fuse@latest

Configuration

Create a configuration file at ~/.config/secret-fuse.conf or config.yaml:

op_account: "my.1password.com"# default 1Password account (optional)secrets:
- reference: "op://VAULT-UUID/ITEM-UUID/FIELD"filename: "secrets.json"max_reads: 1# 0 = unlimitedwritable: true # optional: allow writing back to password managerallowed_cmds: # optional: restrict which commands can read this secret
- "/usr/bin/myapp *"
- "/usr/bin/pyton /opt/server.py"symlink_to: "~/.config/app/secrets.json"# optional: create symlink to secret# op_account: "other.1password.com" # optional: override account for this secret

Writable Secrets

Set writable: true to allow writing to the secret file. Changes are written back to the password manager. A backup of the previous value is created automatically (e.g., field_previous for fields, .bak for document files).

Symlinks

The symlink_to field creates a symlink pointing to the mounted secret file. Supports ~ expansion. The symlink is created on mount and removed on unmount. Only existing symlinks will be replaced; regular files are not overwritten.

1Password Account

The op_account field specifies which 1Password account to use for desktop app integration. It can be set at the top level as a default, or per-secret to override.

Priority: OP_ACCOUNT environment variable > config file op_account

Allowlist Patterns

The allowed_cmds field accepts glob patterns matched against the full command line or executable path:

  • /usr/bin/myapp - exact match
  • python * - any python command
  • */node * - node from any path
  • Empty list or omitted = allow all

Getting 1Password References

  1. List your accounts to get the account URL:
op account list

Use the value from the URL column (e.g., my.1password.com).

  1. List your vaults to get the vault UUID:
op vault list
  1. List items in a vault to get the item UUID:
op item list --vault VAULT-UUID
  1. Get item details to see available fields:
op item get ITEM-UUID

Common fields: password, username, credential, notesPlain

Example

# Get account URL
$ op account list
URL EMAIL
my.1password.com user@example.com
# Get vault UUID
$ op vault list
ID NAME
abc123... Personal
# Get item UUID
$ op item list --vault abc123
ID TITLE
def456... API Key
# Check available fields
$ op item get def456
...
password: ********
...
# Configure
secrets:
- reference: "op://abc123/def456/password"
filename: "api-key.txt"

Usage

# Mount with default path (/tmp/secrets-mount)
secrets-fuse
# Mount with custom path
secrets-fuse -mount /run/user/$(id -u)/secrets
# Mount with explicit config
secrets-fuse -mount /tmp/secrets -config /path/to/config.yaml
# Enable debug logging
secrets-fuse -debug

Flags

  • -mount: Mount point for the secrets filesystem (default: /tmp/secrets-mount)
  • -config: Path to configuration file (default: ~/.config/secret-fuse.conf or config.yaml)
  • -max-reads: Default maximum reads per secret, 0 = unlimited (default: 0)
  • -debug: Enable FUSE debug logging

Unmounting

Press Ctrl+C to unmount. If the filesystem is busy, close any files or terminals using the mount and try again.

About

A FUSE layer for securing secrets from filesystem-based credential stores

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - evict/secrets-fuse: A FUSE layer for securing secrets from filesystem-based credential stores · GitHub
Skip to content

Latest commit

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

secrets-fuse - Secure secrets from filesystem-based credential stores

A FUSE filesystem that exposes secrets from 1Password as virtual files.

Features:

  • Command allowlists - restrict which processes can read each secret
  • Read limits - secrets can self-destruct after N reads
  • Write-back support - update secrets directly through the filesystem

Note

This is a prototype and it is currently limited in the security it provides. While it is still better than a simple filesystem based secret, it is possible to bypass the allowlisting mechanism with a well-timed TOCTOU "swap" attack. Currently looking at improving the security model using fanotify & eBPF for Linux, and ESF for Darwin.

Prerequisites

Enable 1Password Desktop Integration

  1. Open and unlock the 1Password app
  2. Select your account or collection at the top of the sidebar
  3. Navigate to Settings > Developer
  4. Under "Integrate with the 1Password SDKs", select Integrate with other apps
  5. (Optional) For biometric unlock, go to Settings > Security and enable Unlock using Touch ID (macOS) or Windows Hello (Windows)

See 1Password SDK documentation for more details.

Installation

go install github.com/evict/secrets-fuse@latest

Configuration

Create a configuration file at ~/.config/secret-fuse.conf or config.yaml:

op_account: "my.1password.com"# default 1Password account (optional)secrets:
- reference: "op://VAULT-UUID/ITEM-UUID/FIELD"filename: "secrets.json"max_reads: 1# 0 = unlimitedwritable: true # optional: allow writing back to password managerallowed_cmds: # optional: restrict which commands can read this secret
- "/usr/bin/myapp *"
- "/usr/bin/pyton /opt/server.py"symlink_to: "~/.config/app/secrets.json"# optional: create symlink to secret# op_account: "other.1password.com" # optional: override account for this secret

Writable Secrets

Set writable: true to allow writing to the secret file. Changes are written back to the password manager. A backup of the previous value is created automatically (e.g., field_previous for fields, .bak for document files).

Symlinks

The symlink_to field creates a symlink pointing to the mounted secret file. Supports ~ expansion. The symlink is created on mount and removed on unmount. Only existing symlinks will be replaced; regular files are not overwritten.

1Password Account

The op_account field specifies which 1Password account to use for desktop app integration. It can be set at the top level as a default, or per-secret to override.

Priority: OP_ACCOUNT environment variable > config file op_account

Allowlist Patterns

The allowed_cmds field accepts glob patterns matched against the full command line or executable path:

  • /usr/bin/myapp - exact match
  • python * - any python command
  • */node * - node from any path
  • Empty list or omitted = allow all

Getting 1Password References

  1. List your accounts to get the account URL:
op account list

Use the value from the URL column (e.g., my.1password.com).

  1. List your vaults to get the vault UUID:
op vault list
  1. List items in a vault to get the item UUID:
op item list --vault VAULT-UUID
  1. Get item details to see available fields:
op item get ITEM-UUID

Common fields: password, username, credential, notesPlain

Example

# Get account URL
$ op account list
URL EMAIL
my.1password.com user@example.com
# Get vault UUID
$ op vault list
ID NAME
abc123... Personal
# Get item UUID
$ op item list --vault abc123
ID TITLE
def456... API Key
# Check available fields
$ op item get def456
...
password: ********
...
# Configure
secrets:
- reference: "op://abc123/def456/password"
filename: "api-key.txt"

Usage

# Mount with default path (/tmp/secrets-mount)
secrets-fuse
# Mount with custom path
secrets-fuse -mount /run/user/$(id -u)/secrets
# Mount with explicit config
secrets-fuse -mount /tmp/secrets -config /path/to/config.yaml
# Enable debug logging
secrets-fuse -debug

Flags

  • -mount: Mount point for the secrets filesystem (default: /tmp/secrets-mount)
  • -config: Path to configuration file (default: ~/.config/secret-fuse.conf or config.yaml)
  • -max-reads: Default maximum reads per secret, 0 = unlimited (default: 0)
  • -debug: Enable FUSE debug logging

Unmounting

Press Ctrl+C to unmount. If the filesystem is busy, close any files or terminals using the mount and try again.

About

A FUSE layer for securing secrets from filesystem-based credential stores

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - evict/secrets-fuse: A FUSE layer for securing secrets from filesystem-based credential stores · GitHub
Skip to content

Latest commit

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

secrets-fuse - Secure secrets from filesystem-based credential stores

A FUSE filesystem that exposes secrets from 1Password as virtual files.

Features:

  • Command allowlists - restrict which processes can read each secret
  • Read limits - secrets can self-destruct after N reads
  • Write-back support - update secrets directly through the filesystem

Note

This is a prototype and it is currently limited in the security it provides. While it is still better than a simple filesystem based secret, it is possible to bypass the allowlisting mechanism with a well-timed TOCTOU "swap" attack. Currently looking at improving the security model using fanotify & eBPF for Linux, and ESF for Darwin.

Prerequisites

Enable 1Password Desktop Integration

  1. Open and unlock the 1Password app
  2. Select your account or collection at the top of the sidebar
  3. Navigate to Settings > Developer
  4. Under "Integrate with the 1Password SDKs", select Integrate with other apps
  5. (Optional) For biometric unlock, go to Settings > Security and enable Unlock using Touch ID (macOS) or Windows Hello (Windows)

See 1Password SDK documentation for more details.

Installation

go install github.com/evict/secrets-fuse@latest

Configuration

Create a configuration file at ~/.config/secret-fuse.conf or config.yaml:

op_account: "my.1password.com"# default 1Password account (optional)secrets:
- reference: "op://VAULT-UUID/ITEM-UUID/FIELD"filename: "secrets.json"max_reads: 1# 0 = unlimitedwritable: true # optional: allow writing back to password managerallowed_cmds: # optional: restrict which commands can read this secret
- "/usr/bin/myapp *"
- "/usr/bin/pyton /opt/server.py"symlink_to: "~/.config/app/secrets.json"# optional: create symlink to secret# op_account: "other.1password.com" # optional: override account for this secret

Writable Secrets

Set writable: true to allow writing to the secret file. Changes are written back to the password manager. A backup of the previous value is created automatically (e.g., field_previous for fields, .bak for document files).

Symlinks

The symlink_to field creates a symlink pointing to the mounted secret file. Supports ~ expansion. The symlink is created on mount and removed on unmount. Only existing symlinks will be replaced; regular files are not overwritten.

1Password Account

The op_account field specifies which 1Password account to use for desktop app integration. It can be set at the top level as a default, or per-secret to override.

Priority: OP_ACCOUNT environment variable > config file op_account

Allowlist Patterns

The allowed_cmds field accepts glob patterns matched against the full command line or executable path:

  • /usr/bin/myapp - exact match
  • python * - any python command
  • */node * - node from any path
  • Empty list or omitted = allow all

Getting 1Password References

  1. List your accounts to get the account URL:
op account list

Use the value from the URL column (e.g., my.1password.com).

  1. List your vaults to get the vault UUID:
op vault list
  1. List items in a vault to get the item UUID:
op item list --vault VAULT-UUID
  1. Get item details to see available fields:
op item get ITEM-UUID

Common fields: password, username, credential, notesPlain

Example

# Get account URL
$ op account list
URL EMAIL
my.1password.com user@example.com
# Get vault UUID
$ op vault list
ID NAME
abc123... Personal
# Get item UUID
$ op item list --vault abc123
ID TITLE
def456... API Key
# Check available fields
$ op item get def456
...
password: ********
...
# Configure
secrets:
- reference: "op://abc123/def456/password"
filename: "api-key.txt"

Usage

# Mount with default path (/tmp/secrets-mount)
secrets-fuse
# Mount with custom path
secrets-fuse -mount /run/user/$(id -u)/secrets
# Mount with explicit config
secrets-fuse -mount /tmp/secrets -config /path/to/config.yaml
# Enable debug logging
secrets-fuse -debug

Flags

  • -mount: Mount point for the secrets filesystem (default: /tmp/secrets-mount)
  • -config: Path to configuration file (default: ~/.config/secret-fuse.conf or config.yaml)
  • -max-reads: Default maximum reads per secret, 0 = unlimited (default: 0)
  • -debug: Enable FUSE debug logging

Unmounting

Press Ctrl+C to unmount. If the filesystem is busy, close any files or terminals using the mount and try again.

About

A FUSE layer for securing secrets from filesystem-based credential stores

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - evict/secrets-fuse: A FUSE layer for securing secrets from filesystem-based credential stores · GitHub
Skip to content

Latest commit

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

secrets-fuse - Secure secrets from filesystem-based credential stores

A FUSE filesystem that exposes secrets from 1Password as virtual files.

Features:

  • Command allowlists - restrict which processes can read each secret
  • Read limits - secrets can self-destruct after N reads
  • Write-back support - update secrets directly through the filesystem

Note

This is a prototype and it is currently limited in the security it provides. While it is still better than a simple filesystem based secret, it is possible to bypass the allowlisting mechanism with a well-timed TOCTOU "swap" attack. Currently looking at improving the security model using fanotify & eBPF for Linux, and ESF for Darwin.

Prerequisites

Enable 1Password Desktop Integration

  1. Open and unlock the 1Password app
  2. Select your account or collection at the top of the sidebar
  3. Navigate to Settings > Developer
  4. Under "Integrate with the 1Password SDKs", select Integrate with other apps
  5. (Optional) For biometric unlock, go to Settings > Security and enable Unlock using Touch ID (macOS) or Windows Hello (Windows)

See 1Password SDK documentation for more details.

Installation

go install github.com/evict/secrets-fuse@latest

Configuration

Create a configuration file at ~/.config/secret-fuse.conf or config.yaml:

op_account: "my.1password.com"# default 1Password account (optional)secrets:
- reference: "op://VAULT-UUID/ITEM-UUID/FIELD"filename: "secrets.json"max_reads: 1# 0 = unlimitedwritable: true # optional: allow writing back to password managerallowed_cmds: # optional: restrict which commands can read this secret
- "/usr/bin/myapp *"
- "/usr/bin/pyton /opt/server.py"symlink_to: "~/.config/app/secrets.json"# optional: create symlink to secret# op_account: "other.1password.com" # optional: override account for this secret

Writable Secrets

Set writable: true to allow writing to the secret file. Changes are written back to the password manager. A backup of the previous value is created automatically (e.g., field_previous for fields, .bak for document files).

Symlinks

The symlink_to field creates a symlink pointing to the mounted secret file. Supports ~ expansion. The symlink is created on mount and removed on unmount. Only existing symlinks will be replaced; regular files are not overwritten.

1Password Account

The op_account field specifies which 1Password account to use for desktop app integration. It can be set at the top level as a default, or per-secret to override.

Priority: OP_ACCOUNT environment variable > config file op_account

Allowlist Patterns

The allowed_cmds field accepts glob patterns matched against the full command line or executable path:

  • /usr/bin/myapp - exact match
  • python * - any python command
  • */node * - node from any path
  • Empty list or omitted = allow all

Getting 1Password References

  1. List your accounts to get the account URL:
op account list

Use the value from the URL column (e.g., my.1password.com).

  1. List your vaults to get the vault UUID:
op vault list
  1. List items in a vault to get the item UUID:
op item list --vault VAULT-UUID
  1. Get item details to see available fields:
op item get ITEM-UUID

Common fields: password, username, credential, notesPlain

Example

# Get account URL
$ op account list
URL EMAIL
my.1password.com user@example.com
# Get vault UUID
$ op vault list
ID NAME
abc123... Personal
# Get item UUID
$ op item list --vault abc123
ID TITLE
def456... API Key
# Check available fields
$ op item get def456
...
password: ********
...
# Configure
secrets:
- reference: "op://abc123/def456/password"
filename: "api-key.txt"

Usage

# Mount with default path (/tmp/secrets-mount)
secrets-fuse
# Mount with custom path
secrets-fuse -mount /run/user/$(id -u)/secrets
# Mount with explicit config
secrets-fuse -mount /tmp/secrets -config /path/to/config.yaml
# Enable debug logging
secrets-fuse -debug

Flags

  • -mount: Mount point for the secrets filesystem (default: /tmp/secrets-mount)
  • -config: Path to configuration file (default: ~/.config/secret-fuse.conf or config.yaml)
  • -max-reads: Default maximum reads per secret, 0 = unlimited (default: 0)
  • -debug: Enable FUSE debug logging

Unmounting

Press Ctrl+C to unmount. If the filesystem is busy, close any files or terminals using the mount and try again.

About

A FUSE layer for securing secrets from filesystem-based credential stores

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - evict/secrets-fuse: A FUSE layer for securing secrets from filesystem-based credential stores · GitHub
Skip to content

Latest commit

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

secrets-fuse - Secure secrets from filesystem-based credential stores

A FUSE filesystem that exposes secrets from 1Password as virtual files.

Features:

  • Command allowlists - restrict which processes can read each secret
  • Read limits - secrets can self-destruct after N reads
  • Write-back support - update secrets directly through the filesystem

Note

This is a prototype and it is currently limited in the security it provides. While it is still better than a simple filesystem based secret, it is possible to bypass the allowlisting mechanism with a well-timed TOCTOU "swap" attack. Currently looking at improving the security model using fanotify & eBPF for Linux, and ESF for Darwin.

Prerequisites

Enable 1Password Desktop Integration

  1. Open and unlock the 1Password app
  2. Select your account or collection at the top of the sidebar
  3. Navigate to Settings > Developer
  4. Under "Integrate with the 1Password SDKs", select Integrate with other apps
  5. (Optional) For biometric unlock, go to Settings > Security and enable Unlock using Touch ID (macOS) or Windows Hello (Windows)

See 1Password SDK documentation for more details.

Installation

go install github.com/evict/secrets-fuse@latest

Configuration

Create a configuration file at ~/.config/secret-fuse.conf or config.yaml:

op_account: "my.1password.com"# default 1Password account (optional)secrets:
- reference: "op://VAULT-UUID/ITEM-UUID/FIELD"filename: "secrets.json"max_reads: 1# 0 = unlimitedwritable: true # optional: allow writing back to password managerallowed_cmds: # optional: restrict which commands can read this secret
- "/usr/bin/myapp *"
- "/usr/bin/pyton /opt/server.py"symlink_to: "~/.config/app/secrets.json"# optional: create symlink to secret# op_account: "other.1password.com" # optional: override account for this secret

Writable Secrets

Set writable: true to allow writing to the secret file. Changes are written back to the password manager. A backup of the previous value is created automatically (e.g., field_previous for fields, .bak for document files).

Symlinks

The symlink_to field creates a symlink pointing to the mounted secret file. Supports ~ expansion. The symlink is created on mount and removed on unmount. Only existing symlinks will be replaced; regular files are not overwritten.

1Password Account

The op_account field specifies which 1Password account to use for desktop app integration. It can be set at the top level as a default, or per-secret to override.

Priority: OP_ACCOUNT environment variable > config file op_account

Allowlist Patterns

The allowed_cmds field accepts glob patterns matched against the full command line or executable path:

  • /usr/bin/myapp - exact match
  • python * - any python command
  • */node * - node from any path
  • Empty list or omitted = allow all

Getting 1Password References

  1. List your accounts to get the account URL:
op account list

Use the value from the URL column (e.g., my.1password.com).

  1. List your vaults to get the vault UUID:
op vault list
  1. List items in a vault to get the item UUID:
op item list --vault VAULT-UUID
  1. Get item details to see available fields:
op item get ITEM-UUID

Common fields: password, username, credential, notesPlain

Example

# Get account URL
$ op account list
URL EMAIL
my.1password.com user@example.com
# Get vault UUID
$ op vault list
ID NAME
abc123... Personal
# Get item UUID
$ op item list --vault abc123
ID TITLE
def456... API Key
# Check available fields
$ op item get def456
...
password: ********
...
# Configure
secrets:
- reference: "op://abc123/def456/password"
filename: "api-key.txt"

Usage

# Mount with default path (/tmp/secrets-mount)
secrets-fuse
# Mount with custom path
secrets-fuse -mount /run/user/$(id -u)/secrets
# Mount with explicit config
secrets-fuse -mount /tmp/secrets -config /path/to/config.yaml
# Enable debug logging
secrets-fuse -debug

Flags

  • -mount: Mount point for the secrets filesystem (default: /tmp/secrets-mount)
  • -config: Path to configuration file (default: ~/.config/secret-fuse.conf or config.yaml)
  • -max-reads: Default maximum reads per secret, 0 = unlimited (default: 0)
  • -debug: Enable FUSE debug logging

Unmounting

Press Ctrl+C to unmount. If the filesystem is busy, close any files or terminals using the mount and try again.

About

A FUSE layer for securing secrets from filesystem-based credential stores

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - evict/secrets-fuse: A FUSE layer for securing secrets from filesystem-based credential stores · GitHub
Skip to content

Latest commit

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

secrets-fuse - Secure secrets from filesystem-based credential stores

A FUSE filesystem that exposes secrets from 1Password as virtual files.

Features:

  • Command allowlists - restrict which processes can read each secret
  • Read limits - secrets can self-destruct after N reads
  • Write-back support - update secrets directly through the filesystem

Note

This is a prototype and it is currently limited in the security it provides. While it is still better than a simple filesystem based secret, it is possible to bypass the allowlisting mechanism with a well-timed TOCTOU "swap" attack. Currently looking at improving the security model using fanotify & eBPF for Linux, and ESF for Darwin.

Prerequisites

Enable 1Password Desktop Integration

  1. Open and unlock the 1Password app
  2. Select your account or collection at the top of the sidebar
  3. Navigate to Settings > Developer
  4. Under "Integrate with the 1Password SDKs", select Integrate with other apps
  5. (Optional) For biometric unlock, go to Settings > Security and enable Unlock using Touch ID (macOS) or Windows Hello (Windows)

See 1Password SDK documentation for more details.

Installation

go install github.com/evict/secrets-fuse@latest

Configuration

Create a configuration file at ~/.config/secret-fuse.conf or config.yaml:

op_account: "my.1password.com"# default 1Password account (optional)secrets:
- reference: "op://VAULT-UUID/ITEM-UUID/FIELD"filename: "secrets.json"max_reads: 1# 0 = unlimitedwritable: true # optional: allow writing back to password managerallowed_cmds: # optional: restrict which commands can read this secret
- "/usr/bin/myapp *"
- "/usr/bin/pyton /opt/server.py"symlink_to: "~/.config/app/secrets.json"# optional: create symlink to secret# op_account: "other.1password.com" # optional: override account for this secret

Writable Secrets

Set writable: true to allow writing to the secret file. Changes are written back to the password manager. A backup of the previous value is created automatically (e.g., field_previous for fields, .bak for document files).

Symlinks

The symlink_to field creates a symlink pointing to the mounted secret file. Supports ~ expansion. The symlink is created on mount and removed on unmount. Only existing symlinks will be replaced; regular files are not overwritten.

1Password Account

The op_account field specifies which 1Password account to use for desktop app integration. It can be set at the top level as a default, or per-secret to override.

Priority: OP_ACCOUNT environment variable > config file op_account

Allowlist Patterns

The allowed_cmds field accepts glob patterns matched against the full command line or executable path:

  • /usr/bin/myapp - exact match
  • python * - any python command
  • */node * - node from any path
  • Empty list or omitted = allow all

Getting 1Password References

  1. List your accounts to get the account URL:
op account list

Use the value from the URL column (e.g., my.1password.com).

  1. List your vaults to get the vault UUID:
op vault list
  1. List items in a vault to get the item UUID:
op item list --vault VAULT-UUID
  1. Get item details to see available fields:
op item get ITEM-UUID

Common fields: password, username, credential, notesPlain

Example

# Get account URL
$ op account list
URL EMAIL
my.1password.com user@example.com
# Get vault UUID
$ op vault list
ID NAME
abc123... Personal
# Get item UUID
$ op item list --vault abc123
ID TITLE
def456... API Key
# Check available fields
$ op item get def456
...
password: ********
...
# Configure
secrets:
- reference: "op://abc123/def456/password"
filename: "api-key.txt"

Usage

# Mount with default path (/tmp/secrets-mount)
secrets-fuse
# Mount with custom path
secrets-fuse -mount /run/user/$(id -u)/secrets
# Mount with explicit config
secrets-fuse -mount /tmp/secrets -config /path/to/config.yaml
# Enable debug logging
secrets-fuse -debug

Flags

  • -mount: Mount point for the secrets filesystem (default: /tmp/secrets-mount)
  • -config: Path to configuration file (default: ~/.config/secret-fuse.conf or config.yaml)
  • -max-reads: Default maximum reads per secret, 0 = unlimited (default: 0)
  • -debug: Enable FUSE debug logging

Unmounting

Press Ctrl+C to unmount. If the filesystem is busy, close any files or terminals using the mount and try again.

About

A FUSE layer for securing secrets from filesystem-based credential stores

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - evict/secrets-fuse: A FUSE layer for securing secrets from filesystem-based credential stores · GitHub
Skip to content

Latest commit

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

secrets-fuse - Secure secrets from filesystem-based credential stores

A FUSE filesystem that exposes secrets from 1Password as virtual files.

Features:

  • Command allowlists - restrict which processes can read each secret
  • Read limits - secrets can self-destruct after N reads
  • Write-back support - update secrets directly through the filesystem

Note

This is a prototype and it is currently limited in the security it provides. While it is still better than a simple filesystem based secret, it is possible to bypass the allowlisting mechanism with a well-timed TOCTOU "swap" attack. Currently looking at improving the security model using fanotify & eBPF for Linux, and ESF for Darwin.

Prerequisites

Enable 1Password Desktop Integration

  1. Open and unlock the 1Password app
  2. Select your account or collection at the top of the sidebar
  3. Navigate to Settings > Developer
  4. Under "Integrate with the 1Password SDKs", select Integrate with other apps
  5. (Optional) For biometric unlock, go to Settings > Security and enable Unlock using Touch ID (macOS) or Windows Hello (Windows)

See 1Password SDK documentation for more details.

Installation

go install github.com/evict/secrets-fuse@latest

Configuration

Create a configuration file at ~/.config/secret-fuse.conf or config.yaml:

op_account: "my.1password.com"# default 1Password account (optional)secrets:
- reference: "op://VAULT-UUID/ITEM-UUID/FIELD"filename: "secrets.json"max_reads: 1# 0 = unlimitedwritable: true # optional: allow writing back to password managerallowed_cmds: # optional: restrict which commands can read this secret
- "/usr/bin/myapp *"
- "/usr/bin/pyton /opt/server.py"symlink_to: "~/.config/app/secrets.json"# optional: create symlink to secret# op_account: "other.1password.com" # optional: override account for this secret

Writable Secrets

Set writable: true to allow writing to the secret file. Changes are written back to the password manager. A backup of the previous value is created automatically (e.g., field_previous for fields, .bak for document files).

Symlinks

The symlink_to field creates a symlink pointing to the mounted secret file. Supports ~ expansion. The symlink is created on mount and removed on unmount. Only existing symlinks will be replaced; regular files are not overwritten.

1Password Account

The op_account field specifies which 1Password account to use for desktop app integration. It can be set at the top level as a default, or per-secret to override.

Priority: OP_ACCOUNT environment variable > config file op_account

Allowlist Patterns

The allowed_cmds field accepts glob patterns matched against the full command line or executable path:

  • /usr/bin/myapp - exact match
  • python * - any python command
  • */node * - node from any path
  • Empty list or omitted = allow all

Getting 1Password References

  1. List your accounts to get the account URL:
op account list

Use the value from the URL column (e.g., my.1password.com).

  1. List your vaults to get the vault UUID:
op vault list
  1. List items in a vault to get the item UUID:
op item list --vault VAULT-UUID
  1. Get item details to see available fields:
op item get ITEM-UUID

Common fields: password, username, credential, notesPlain

Example

# Get account URL
$ op account list
URL EMAIL
my.1password.com user@example.com
# Get vault UUID
$ op vault list
ID NAME
abc123... Personal
# Get item UUID
$ op item list --vault abc123
ID TITLE
def456... API Key
# Check available fields
$ op item get def456
...
password: ********
...
# Configure
secrets:
- reference: "op://abc123/def456/password"
filename: "api-key.txt"

Usage

# Mount with default path (/tmp/secrets-mount)
secrets-fuse
# Mount with custom path
secrets-fuse -mount /run/user/$(id -u)/secrets
# Mount with explicit config
secrets-fuse -mount /tmp/secrets -config /path/to/config.yaml
# Enable debug logging
secrets-fuse -debug

Flags

  • -mount: Mount point for the secrets filesystem (default: /tmp/secrets-mount)
  • -config: Path to configuration file (default: ~/.config/secret-fuse.conf or config.yaml)
  • -max-reads: Default maximum reads per secret, 0 = unlimited (default: 0)
  • -debug: Enable FUSE debug logging

Unmounting

Press Ctrl+C to unmount. If the filesystem is busy, close any files or terminals using the mount and try again.

About

A FUSE layer for securing secrets from filesystem-based credential stores

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - evict/secrets-fuse: A FUSE layer for securing secrets from filesystem-based credential stores · GitHub
Skip to content

Latest commit

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

secrets-fuse - Secure secrets from filesystem-based credential stores

A FUSE filesystem that exposes secrets from 1Password as virtual files.

Features:

  • Command allowlists - restrict which processes can read each secret
  • Read limits - secrets can self-destruct after N reads
  • Write-back support - update secrets directly through the filesystem

Note

This is a prototype and it is currently limited in the security it provides. While it is still better than a simple filesystem based secret, it is possible to bypass the allowlisting mechanism with a well-timed TOCTOU "swap" attack. Currently looking at improving the security model using fanotify & eBPF for Linux, and ESF for Darwin.

Prerequisites

Enable 1Password Desktop Integration

  1. Open and unlock the 1Password app
  2. Select your account or collection at the top of the sidebar
  3. Navigate to Settings > Developer
  4. Under "Integrate with the 1Password SDKs", select Integrate with other apps
  5. (Optional) For biometric unlock, go to Settings > Security and enable Unlock using Touch ID (macOS) or Windows Hello (Windows)

See 1Password SDK documentation for more details.

Installation

go install github.com/evict/secrets-fuse@latest

Configuration

Create a configuration file at ~/.config/secret-fuse.conf or config.yaml:

op_account: "my.1password.com"# default 1Password account (optional)secrets:
- reference: "op://VAULT-UUID/ITEM-UUID/FIELD"filename: "secrets.json"max_reads: 1# 0 = unlimitedwritable: true # optional: allow writing back to password managerallowed_cmds: # optional: restrict which commands can read this secret
- "/usr/bin/myapp *"
- "/usr/bin/pyton /opt/server.py"symlink_to: "~/.config/app/secrets.json"# optional: create symlink to secret# op_account: "other.1password.com" # optional: override account for this secret

Writable Secrets

Set writable: true to allow writing to the secret file. Changes are written back to the password manager. A backup of the previous value is created automatically (e.g., field_previous for fields, .bak for document files).

Symlinks

The symlink_to field creates a symlink pointing to the mounted secret file. Supports ~ expansion. The symlink is created on mount and removed on unmount. Only existing symlinks will be replaced; regular files are not overwritten.

1Password Account

The op_account field specifies which 1Password account to use for desktop app integration. It can be set at the top level as a default, or per-secret to override.

Priority: OP_ACCOUNT environment variable > config file op_account

Allowlist Patterns

The allowed_cmds field accepts glob patterns matched against the full command line or executable path:

  • /usr/bin/myapp - exact match
  • python * - any python command
  • */node * - node from any path
  • Empty list or omitted = allow all

Getting 1Password References

  1. List your accounts to get the account URL:
op account list

Use the value from the URL column (e.g., my.1password.com).

  1. List your vaults to get the vault UUID:
op vault list
  1. List items in a vault to get the item UUID:
op item list --vault VAULT-UUID
  1. Get item details to see available fields:
op item get ITEM-UUID

Common fields: password, username, credential, notesPlain

Example

# Get account URL
$ op account list
URL EMAIL
my.1password.com user@example.com
# Get vault UUID
$ op vault list
ID NAME
abc123... Personal
# Get item UUID
$ op item list --vault abc123
ID TITLE
def456... API Key
# Check available fields
$ op item get def456
...
password: ********
...
# Configure
secrets:
- reference: "op://abc123/def456/password"
filename: "api-key.txt"

Usage

# Mount with default path (/tmp/secrets-mount)
secrets-fuse
# Mount with custom path
secrets-fuse -mount /run/user/$(id -u)/secrets
# Mount with explicit config
secrets-fuse -mount /tmp/secrets -config /path/to/config.yaml
# Enable debug logging
secrets-fuse -debug

Flags

  • -mount: Mount point for the secrets filesystem (default: /tmp/secrets-mount)
  • -config: Path to configuration file (default: ~/.config/secret-fuse.conf or config.yaml)
  • -max-reads: Default maximum reads per secret, 0 = unlimited (default: 0)
  • -debug: Enable FUSE debug logging

Unmounting

Press Ctrl+C to unmount. If the filesystem is busy, close any files or terminals using the mount and try again.

About

A FUSE layer for securing secrets from filesystem-based credential stores

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages