T09 · Insecure Skill Coding Practices
- Location
scripts/login.py:311- Finding
Arbitrary File Deletion Through the Unrestricted Cookie Path
- Content
View full analysis
Vulnerability Details
File Location:
scripts/__main__.py:58-65,scripts/__main__.py:181-187,scripts/__main__.py:576, andscripts/login.py:311-323
Vulnerability Type: Unrestricted filesystem path used in a destructive operation
Risk Level: HighVulnerable Code
python def _cookie_path(args) -> str: profile = _profile(args) paths = profile_paths(profile) if profile: os.environ["XHS_PROFILE"] = profile if getattr(args, "cookie", None): return args.cookie return str(paths.cookie_path)python def cmd_logout(args): """Delete login state.""" result = login.logout( cookie_path=_cookie_path(args), user_data_dir=_user_data_dir(args), ) print(format_output(result)) return 0python parser.add_argument("--cookie", "-c", help="Cookie file path", default=None)python def logout(cookie_path=None, user_data_dir=None): """Delete persistent browser data and the cookie file to reset login state.""" import shutil paths = profile_paths(env_profile()) data_dir = user_data_dir or str(paths.user_data_dir) if os.path.exists(data_dir): shutil.rmtree(data_dir) path = cookie_path or DEFAULT_COOKIE_PATH if os.path.exists(path): os.remove(path) strategy_file = os.path.join( os.path.expanduser("~"), ".xiaohongshu", "strategy.json", ) if os.path.exists(strategy_file): os.remove(strategy_file) return {"status": "ok", "message": "Login state cleared"}Technical Analysis
The global
--cookieoption accepts an arbitrary filesystem path._cookie_path()returns that path without canonicalization, ownership verification, extension checking, symlink rejection, or enforcement that it resides inside a Skill-managed profile directory.The
logoutcommand passes this unrest ...[truncated 1680 chars]- Remediation
View remediation
Remediation Suggestions
- Do not permit the global
--cookieoverride to select the deletion target forlogout. - Derive logout targets exclusively from a validated profile name and the configured Skill state root.
- Resolve both the candidate path and allowed root with
Path.resolve()and verify that the candidate is strictly beneath the allowed root. - Reject symlinks and unexpected file types before deletion.
- Require the target filename to match the expected cookie filename, such as
cookies.json. - Refuse to delete an existing file unless its structure is a valid Skill cookie backup.
- Add an explicit destructive-operation confirmation that displays the canonical target.
- Add regression tests covering absolute paths,
..traversal, symlinks, profile-root paths, and unrelated existing files.
A hardened design should resemble:
python allowed_root = profile_root.resolve() target = paths.cookie_path.resolve() if target.parent != allowed_profile_directory.resolve(): raise ValueError("Cookie deletion target is outside the selected profile") if target.is_symlink() or target.name != "cookies.json": raise ValueError("Invalid cookie deletion target")- Do not permit the global
