tonhowtf/omniget · error
plugin id must not contain '..
Error message
plugin id must not contain '..': {plugin_id:?} What it means
Even if each character is legal, an id containing the substring ".." is rejected because it can form traversal sequences when concatenated into paths (e.g. 'a..b' plus separators). validate_plugin_id bails with the offending id embedded.
Solutions
- Remove '..' from the id before use
- Validate with validate_plugin_id before constructing any path from the id
- Reject the manifest/plugin whose id contains '..'
Example fix
// before
let dir = plugin_dir("foo..bar")?; // bails
// after
ensure!(!id.contains(".."), "plugin id must not contain '..'");
let dir = plugin_dir(&id)?; Defensive patterns
Strategy: validation
Validate before calling
ensure!(!plugin_id.contains(".."), "plugin id must not contain '..': {plugin_id:?}"); Type guard
fn no_dotdot(id: &str) -> bool { !id.contains("..") } Try / catch
let dir = plugin_dir(&id).with_context(|| format!("traversal-risk plugin id {id:?}"))?; Prevention
- Reject '..' substrings in any path-bound identifier
- Always call validate_plugin_id before path joins
- Audit manifest ids in CI
When it happens
Trigger: Passing any id containing ".." (e.g. "foo..bar", "a/../b" already caught earlier) to plugin_dir/validate_plugin_id.
Common situations: User-supplied ids attempting traversal; accidental double-dot typos in manifest ids; concatenated path fragments used as ids.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- external_data_cache: plugin_id/namespace must not contain…
- plugin id must not be a relative path component
- external_data_cache: plugin_id must not be empty
- external_data_cache: namespace must not be empty
- plugin id must not be empty
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/01db34b85858505d.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/plugin_loader.rs:245
///
/// Allowlist e nao blocklist de proposito: o conjunto de ids reais e pequeno e
/// conhecido (`courses`, `study`, `telegram`, `convert`, `misc`), e uma
/// blocklist erra por omissao a cada codificacao nova.
pub fn validate_plugin_id(plugin_id: &str) -> anyhow::Result<()> {
if plugin_id.is_empty() {
anyhow::bail!("plugin id must not be empty");
}
if plugin_id == "." || plugin_id == ".." || plugin_id.starts_with('.') {
anyhow::bail!("plugin id must not be a relative path component: {plugin_id:?}");
}
if let Some(bad) = plugin_id
.chars()
.find(|c| !c.is_ascii_alphanumeric() && !matches!(c, '.' | '_' | '-'))
{
anyhow::bail!("plugin id contains an illegal character {bad:?}: {plugin_id:?}");
}
if plugin_id.contains("..") {
anyhow::bail!("plugin id must not contain '..': {plugin_id:?}");
}
Ok(())
}
fn load_single_plugin(
plugin_dir: &Path,
host: Arc<dyn PluginHost>,
) -> Result<LoadedPlugin, PluginLoadError> {
let manifest_path = plugin_dir.join("plugin.json");
let manifest_str = fs::read_to_string(&manifest_path).map_err(|e| {
PluginLoadError::simple("manifest_read", format!("Cannot read plugin.json: {e}"))
})?;
let manifest: PluginManifest = serde_json::from_str(&manifest_str).map_err(|e| {
PluginLoadError::simple("manifest_parse", format!("Invalid plugin.json: {e}"))
})?;
let lib_path =
find_native_lib(plugin_dir, manifest.rust_crate.as_deref()).ok_or_else(|| {View on GitHub (pinned to 8600b91f42)