hasura/graphql-engine · warning

plugin name %q not allowed

Error message

plugin name %q not allowed

What it means

LoadPluginByName rejects the requested plugin name via IsSafePluginName before touching the filesystem. This is a path-traversal guard: names containing slashes, '..' segments, absolute paths, or characters outside the allowed pattern are refused so they cannot escape the plugins index directory.

Source

Thrown at cli/plugins/scanner.go:83

	}

	files, err := c.findPluginManifestFiles(indexDir)
	if err != nil {
		return nil, errors.E(op, fmt.Errorf("failed to scan plugins in index directory: %w", err))
	}

	return c.LoadPlugins(files), nil
}

// LoadPluginByName loads a plugins index file by its name. When plugin
// file not found, it returns an error that can be checked with stderrors.Is(err, fs.ErrNotExist).
func (c *Config) LoadPluginByName(pluginName string) (*PluginVersions, error) {
	var op errors.Op = "plugins.Config.LoadPluginByName"

	c.Logger.Debugf("loading plugin %s", pluginName)

	if !IsSafePluginName(pluginName) {
		return nil, errors.E(op, fmt.Errorf("plugin name %q not allowed", pluginName))
	}

	files, err := c.findPluginManifestFiles(c.Paths.IndexPluginsPath())
	if err != nil {
		return nil, errors.E(op, fmt.Errorf("failed to scan plugins in index directory: %w", err))
	}

	ps := c.LoadPlugins(files, pluginName)
	if _, ok := ps[pluginName]; !ok {
		return nil, errors.E(op, os.ErrNotExist)
	}

	return ps[pluginName], nil
}

func (c *Config) LoadPlugins(files []string, pluginName ...string) Plugins {
	c.Logger.Debugf("loading plugins")

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Sanitize/validate the name with plugins.IsSafePluginName before calling the API
  2. Strip path separators and '..' segments from user input, or reject such input at the boundary
  3. Use the exact plugin name shown by `plugin list` (usually lowercase alphanumeric with dashes)

Example fix

// before
p, err := cfg.GetPlugin(r.URL.Query().Get("name")) // "../etc/passwd" -> error

// after
name := r.URL.Query().Get("name")
if !plugins.IsSafePluginName(name) {
	http.Error(w, "invalid plugin name", http.StatusBadRequest)
	return
}
p, err := cfg.GetPlugin(name)
Defensive patterns

Strategy: validation

Validate before calling

if !plugins.IsSafePluginName(name) { return fmt.Errorf("invalid plugin name: %q", name) }

Type guard

func isValidPluginName(s string) bool {
	if s == "" || len(s) > 100 { return false }
	if strings.ContainsAny(s, "/\\") || strings.Contains(s, "..") { return false }
	for _, r := range s {
		if !(r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || r == '-') { return false }
	}
	return true
}

Prevention

When it happens

Trigger: Calling Config.GetPlugin or Config.Upgrade with a name like "../secrets", "/etc/passwd", "foo/bar", an empty string, or any name failing the safe-name regex.

Common situations: User-supplied plugin names passed unvalidated from a script or web form; typos including path separators; programmatically constructed names that accidentally include a leading './' or Windows-style backslashes.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/92dc5e46cf64a2ad. Report an issue: GitHub.