A standing request asked for a SamplerCustomAdvanced version of the node, so a
custom guider and scheduler could be used. The scheduler half already shipped:
custom_sigmas takes a SIGMAS input and the schedule is sampled, not just
counted. The gap was the guider, and it is the half that matters -- a guider is
the only way to reach BasicGuider with no negative and no CFG, DualCFGGuider,
or anything another pack provides.
This does it with a node that outputs NOISE rather than a second sampler.
SamplerCustomAdvanced consumes one, and so does AddNoise.
A second sampler node was the obvious shape and would have worked: the segment
loop already routes through CFGGuider.sample, because comfy.sample.sample
builds a guider and calls it, so accepting one would have been a substitution
rather than a new mechanism. It was not worth it. A NOISE object is forty lines
against a second wall of shader widgets, five frontend files that name nodes
explicitly, and a sampling seam through the pipeline -- and it composes with
everything in the custom sampling family instead of only with itself.
What it covers is the node's default configuration exactly: one shader stage,
painted into the noise a run starts from. That is pinned bit for bit against
the Direct node across eps, flow and AV latents, presets, batch_index and
progressions, so a seed means the same thing on both. What it cannot do is
stages, because a NOISE object is asked for noise once, before any sampling --
the sampler's stages re-enter the shader at segment boundaries partway through.
The node says so, and so do the README and the tooltips.
Two pieces were lifted out rather than copied: build_shader_params, next to the
reader that owns the params dict, and _paint/starting_noise in the pipeline,
where the painting loop was already written twice. The Direct node is sixty-odd
lines shorter for it. Both extractions were checked against the golden suite
before anything was built on them.
The equivalence test earned its keep immediately. Presets set stage_progression,
and stage_progression shapes a single stage -- it sits at the start of the
trajectory and is drawn from there -- so ignoring it made preset: roam mean two
different things on the two nodes. It is now an input here, with its own wording
because a ramp across stages is not what it does with one. That also showed the
Direct node's tooltip has always been wrong to say it needs more than one stage
to do anything; the tooltip is corrected and the sampling is untouched, which is
how roam and video have always behaved.
Also dropped a refusal check copied into starting_noise: unlike run, there is no
sampling to protect there, and the generator raises the same error one call
down. And _STREAM_SEED_STRIDE turned out to have nothing pinning it anywhere --
the nested golden case paints only the spatial stream, so zeroing the offset
changed nothing in the suite. It has a test now, feeding two identical streams
so the inputs cannot explain the difference.
Verified on H3 through BasicGuider, KSamplerSelect and BasicScheduler into
SamplerCustomAdvanced: seven steps, coherent output.
example_workflows/MiniMaxH3_CustomSampling_SNK_Source.json is that run, and
needs core nodes and this pack and nothing else.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Added OverflowError handling for seed conversion to prevent crashes with infinite inputs.
- Added explicit NaN/Inf checks for float parameters before clamping, as min/max operations propagate NaN.
- Added NaN/Inf checks for seeds to prevent invalid conversions.
- Validate and clamp `seed` and `base_seed` parameters to the safe 64-bit integer range [-9e18, 9e18] to prevent PyTorch `RuntimeError` crashes.
- Enable and enforce clamping for float parameters (`scale`, `warp_strength`, etc.) to reasonable bounds (+/- 1,000,000) to prevent numerical instability or Infinity/NaN propagation.
- Update `shader_params_reader.py` to implement these checks in `validate_and_sanitize_params`.
Fixes a vulnerability where `ShaderParamsReader.random_val` and `CurlNoiseGenerator.random_val` were calling `torch.manual_seed()` unnecessarily. These helper functions use deterministic math (sin/frac hashing) and do not rely on the PyTorch RNG state. The unnecessary `manual_seed` call was resetting the global random state as a side effect, potentially affecting other components or leading to predictable sequences if interleaved with other random operations.
- Removed `torch.manual_seed` from `ShaderParamsReader.random_val` in `shader_params_reader.py`
- Removed `torch.manual_seed` from internal `random_val` in `shaders/curl_noise.py`
- Added regression test `verification/verify_seed_reset.py`
- Documented in `.jules/sentinel.md`
- Addressed review feedback regarding `shape_type` integer bypass.
- Implemented `LEGACY_SHAPE_MAPPING` to strictly validate integer inputs (1, 2, 3) and map them to their string equivalents.
- Invalid integers now default to 'none', consistent with the allowlist policy.
- Fixed import logic in `verification/verify_params_validation.py` to handle torch dependency check correctly.
- Added regression tests for legacy and invalid integer shape types.
🚨 Severity: HIGH
💡 Vulnerability: String parameters (`shader_type`, `shape_type`, `colorScheme`) were read without validation against predefined allowed values. This could allow unexpected strings to propagate through the system, potentially causing application crashes (DoS) or unexpected behavior in downstream components.
🎯 Impact: Prevents processing of malformed or malicious configuration inputs that could disrupt service availability or logic integrity.
🔧 Fix: Implemented strict Allowlist Validation in `ShaderParamsReader.validate_and_sanitize_params`. Invalid inputs now default to safe values (e.g., "tensor_field", "none").
✅ Verification: Added `verification/verify_params_validation.py` which confirms that invalid strings are now sanitized while valid inputs are preserved.
- Enforce input validation for direct parameters in `DirectShaderNoiseKSampler`.
- Update `ShaderParamsReader.validate_and_sanitize_params` to check `shaderOctaves` alias.
- Clamps `octaves` to 20 to prevent resource exhaustion.
- Implemented `validate_and_sanitize_params` in `ShaderParamsReader`.
- Clamped `octaves` parameter to a safe range (1-20) and cast to integer to prevent infinite loops.
- Ensured type safety for other critical parameters (`scale`, `intensity`, etc.).
- Prevented potential resource exhaustion attacks via malformed `shader_params.json`.
Restrict `get_shader_params` to only allow reading `.json` files that are:
1. Physically located within the extension directory (preventing symlink bypass).
2. Located within the `data/` subdirectory or are the default `shader_params.json` in the extension root (enforcing least privilege).
This prevents potential path traversal, symlink attacks, or unauthorized file reads within the extension directory.
- Added strict file extension check.
- Added strict directory scope check using `os.path.commonpath`.
- Implemented robust case-sensitive-aware comparison using `os.path.normcase`.
- Updated `.jules/sentinel.md` with security learnings.
Restrict `get_shader_params` to only allow reading `.json` files that are either located within the `data/` subdirectory or are the default `shader_params.json` in the extension root. This prevents potential path traversal or arbitrary file read vulnerabilities within the extension directory.
- Added strict file extension check.
- Added strict directory scope check using `os.path.commonpath`.
- Implemented robust case-sensitive-aware comparison using `os.path.normcase` to handle cross-platform casing variations safely (preventing bypasses on Linux while supporting Windows).
- Updated `.jules/sentinel.md` with security learnings.
Restrict `get_shader_params` to only allow reading `.json` files that are either located within the `data/` subdirectory or are the default `shader_params.json` in the extension root. This prevents potential path traversal or arbitrary file read vulnerabilities within the extension directory.
- Added strict file extension check.
- Added strict directory scope check using `os.path.commonpath`.
- Implemented robust case-insensitive comparison using `.lower()` to handle cross-platform casing variations (e.g. `Data/` vs `data/` on Linux).
- Updated `.jules/sentinel.md` with security learnings.
Restrict `get_shader_params` to only allow reading `.json` files that are either located within the `data/` subdirectory or are the default `shader_params.json` in the extension root. This prevents potential path traversal or arbitrary file read vulnerabilities within the extension directory.
- Added strict file extension check.
- Added strict directory scope check using `os.path.commonpath`.
- Updated `.jules/sentinel.md` with security learnings.
Optimized `_interpolate_colors` in `ShaderParamsReader` to use `torch.bucketize` and vectorized indexing instead of iterating over color stops. This improves performance from O(Stops) to O(1) in terms of kernel launches/Python overhead.
Updated `CurlNoiseGenerator` to use the optimized shared implementation instead of its own slower local version.
Also fixed a regression in `apply_shape_mask` hexgrid calculation.
Sanitized `custom_path` input in `ShaderParamsReader.get_shader_params` to prevent reading arbitrary files outside the extension directory.
- Uses `os.path.realpath` to resolve symlinks and absolute paths.
- Uses `os.path.commonpath` to ensure the resolved path is within the allowed `EXTENSION_DIR`.
- Implements a fail-safe fallback to the default parameters file if a traversal attempt is detected.
- Includes error handling for potential `ValueError` on Windows (cross-drive paths).