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