Remove owner filtering from recipe listing (security fix)

The owner field from recipe content could be spoofed to hide recipes
from users or make recipes appear to belong to someone else.

For L1, all recipes in cache are now visible to authenticated users.
Ownership tracking should use the naming service or cache metadata,
not untrusted data from recipe content.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-12 15:33:39 +00:00
parent 6adef63fad
commit 87ff3d5d14

View File

@@ -51,6 +51,9 @@ class RecipeService:
return stripped.startswith('(')
return False
import logging
logger = logging.getLogger(__name__)
if is_sexp_format(content):
# Parse S-expression
try:
@@ -58,7 +61,9 @@ class RecipeService:
recipe_data = compiled.to_dict()
recipe_data["sexp"] = content
recipe_data["format"] = "sexp"
logger.info(f"Parsed sexp recipe {recipe_id[:16]}..., keys: {list(recipe_data.keys())}")
except (ParseError, CompileError) as e:
logger.warning(f"Failed to parse sexp recipe {recipe_id[:16]}...: {e}")
return {"error": str(e), "recipe_id": recipe_id}
else:
# Parse YAML
@@ -107,15 +112,11 @@ class RecipeService:
logger.debug(f"Attempting to get recipe {cid[:16]}...")
recipe = await self.get_recipe(cid)
if recipe and not recipe.get("error"):
owner = recipe.get("owner")
# Filter by actor - L1 is per-user
# Note: S-expression recipes don't have owner field, so owner=None
# means the recipe is shared/public and visible to all users
if actor_id is None or owner is None or owner == actor_id:
recipes.append(recipe)
logger.info(f"Recipe {cid[:16]}... included (owner={owner}, actor={actor_id})")
else:
logger.info(f"Recipe {cid[:16]}... filtered out (owner={owner}, actor={actor_id})")
# Don't trust owner from recipe content - could be spoofed
# For L1, recipes in cache are visible to all authenticated users
# (ownership is tracked via naming service, not recipe content)
recipes.append(recipe)
logger.info(f"Recipe {cid[:16]}... included")
elif recipe and recipe.get("error"):
logger.warning(f"Recipe {cid[:16]}... has error: {recipe.get('error')}")
else: