PyPI / modal / 1.6.3.dev1

modal 1.6.3.dev1

Source
https://github.com/modal-labs/modal-client
Artifact scanned
modal-1.6.3.dev1-py3-none-any.whl (wheel · 1.0 MB · SHA-256 3746fc05d80a…)
Compared with
modal-1.6.3.dev0-py3-none-any.whl (0 signals introduced since)
Files
233 scanned, 7 skipped (binary, oversized, or unrecognised)
Signals
1 critical · 0 warn · 26 info
Scan time
11.5 s
LLM review
Reviewed by claude-haiku-5-5 (Anthropic): 9 of 9 warn and critical signals; 8 demoted to info.
Disclude version
4.3.0
Scanned (UTC)
2026-10-23 11:57

Signals

Ordered by severity, then signals introduced in this release. Hidden characters are shown as ⟨U+…⟩.

  1. critical dynamic-execution modal/cli/secret.py:213:27

    `os.system` called on a non-literal command — runtime-determined shell invocation (ast pass, confidence 0.85)

                input("Pressing enter will open an external editor to allow you to edit the secret value...")
                status_code = os.system(bufferfile.name)
    
            if status_code != 0:
    likely benign LLM, confidence 0.60 Launches an external editor on a temporary buffer file to edit a secret value.
    Reasoning

    os.system runs a value whose name is bufferfile.name, a temporary file. The snippet looks truncated, since running the temp file path directly is odd. In context this is most likely the interactive external-editor flow for editing a secret value, not an attacker-controlled command, but the snippet alone does not fully settle the command construction.

  2. info warn → info by review frame-introspection modal/_runtime/container_io_manager.py:1085:29

    `inspect.currentframe` — call-stack frame introspection (ast pass, confidence 0.70)

    
                current_frame = inspect.currentframe()
                if current_frame is not None:
                    frame = current_frame.f_back
    likely benign LLM, confidence 0.85 Walks one frame up the call stack via inspect.currentframe().f_back.
    Reasoning

    inspect.currentframe() followed by f_back is a common way to find the caller's frame for logging or attribution. Nothing in the snippet decodes, executes, or reaches the network.

  3. info warn → info by review frame-introspection modal/_utils/async_utils.py:221:13

    `inspect.stack` — call-stack frame introspection (ast pass, confidence 0.70)

        # Get the current call stack
        stack = inspect.stack()
    
        # Get the absolute path of this module to filter it out
    likely benign LLM, confidence 0.85 Captures the call stack so the module can filter out its own frames.
    Reasoning

    inspect.stack() is used to walk the call stack and filter out this module's own frames, a typical pattern for locating the external caller. The snippet shows no malicious behaviour.

  4. info warn → info by review frame-introspection modal/_utils/deprecation.py:35:21

    `sys._getframe` — call-stack frame introspection (ast pass, confidence 0.70)

            try:
                frame = sys._getframe()
                while frame is not None and _is_internal_frame(frame):
                    frame = frame.f_back
    likely benign LLM, confidence 0.90 Walks sys._getframe() past internal frames to find the user call site for a deprecation warning.
    Reasoning

    sys._getframe() is walked until internal frames are skipped, which is the standard way to attribute a deprecation warning to the user's call site. This is benign.

  5. info critical → info by review dynamic-import modal/_utils/function_utils.py:230:58

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

                self._file = os.path.abspath(module.__file__)
                package_paths = {os.path.abspath(p) for p in __import__(module.__package__).__path__}
                # There might be multiple package paths in some weird cases
                base_dirs = [
    likely benign LLM, confidence 0.80 Calls __import__ on the module's own package name to read its __path__ for file-path computation.
    Reasoning

    __import__ is applied to module.__package__ of an already-loaded module in order to read its __path__. The name comes from the module's own metadata, not from untrusted input, so this is an ordinary package-path lookup. The critical severity is overstated.

  6. info critical → info by review dynamic-import modal/_vendor/cloudpickle.py:478:5

    `__import__` called on a non-literal expression (ast pass, confidence 0.70)

        # module.
        __import__(name)
        return sys.modules[name]
    likely benign LLM, confidence 0.90 Vendored cloudpickle helper that imports a module by its name and returns it from sys.modules.
    Reasoning

    This is cloudpickle's subimport helper, which imports a module by name during unpickling so that sys.modules can be used. It is a known, legitimate vendored pattern.

  7. info critical → info by review dynamic-execution modal/_vendor/tblib.py:150:20

    `compile` called on a constructed string (ast pass, confidence 0.80)

                f_code = current.tb_frame.f_code
                code = compile('\n' * (current.tb_lineno - 1) + 'raise __traceback_maker', current.tb_frame.f_code.co_filename, 'exec')
                if hasattr(code, 'replace'):
                    # Python 3.8 and newer
    likely benign LLM, confidence 0.85 Compiles a padding-plus-raise stub to rebuild a traceback at the correct line number.
    Reasoning

    tblib is a vendored traceback-serialisation library. It compiles a stub with padded newlines so that a synthetic traceback has the correct line number. This is its documented technique and is not obfuscated malware.

  8. info warn → info by review dynamic-execution modal/_vendor/tblib.py:175:17

    `exec` called on a non-literal expression (ast pass, confidence 0.70)

                try:
                    exec(code, dict(current.tb_frame.f_globals), dict(current.tb_frame.f_locals))  # noqa: S102
                except Exception:
                    next_tb = sys.exc_info()[2].tb_next
    likely benign LLM, confidence 0.80 Executes the synthetic stub in copied frame globals and locals to rebuild a traceback.
    Reasoning

    exec runs the synthetic traceback-maker code inside copies of the frame's globals and locals. This is the mechanism tblib uses to reconstruct traceback objects. It is legitimate library behaviour in a vendored dependency.

  9. info unicode-invisible modal/_watcher.py:68:12

    U+FE0F VARIATION SELECTOR-16 (invisible payload carrier) in source (in string/comment) (raw pass, confidence 0.54)

    def _print_watched_paths(paths: set[Path]):
        msg = "⟨U+FE0F⟩⟨U+FE0F⟩⚡⟨U+FE0F⟩ Serving... hit Ctrl-C to stop!"
    
        output_tree = Tree(msg, guide_style="gray50")
  10. info unicode-invisible modal/_watcher.py:68:15

    U+FE0F VARIATION SELECTOR-16 (invisible payload carrier) in source (in string/comment) (raw pass, confidence 0.54)

    def _print_watched_paths(paths: set[Path]):
        msg = "⟨U+FE0F⟩⟨U+FE0F⟩⚡⟨U+FE0F⟩ Serving... hit Ctrl-C to stop!"
    
        output_tree = Tree(msg, guide_style="gray50")
  11. info warn → info by review dynamic-attribute modal/cli/import_refs.py:187:55

    reach-by-name through `vars.get` (ast pass, confidence 0.60)

    def _is_lazy_import(module: types.ModuleType, name: str) -> bool:
        return _LazyImportType is not None and isinstance(vars(module).get(name), _LazyImportType)
    likely benign LLM, confidence 0.90 Looks up a module attribute by name to test whether it is a lazy-import object.
    Reasoning

    vars(module).get(name) is a plain attribute lookup on a module, used to check whether a name is a lazy import. This is ordinary reflection with no sensitive effect.

  12. line length 613 characters (raw pass, confidence 0.50)

        def HasField(self, field_name: typing_extensions.Literal["http", b"http", "http_disconnect", b"http_disconnect", "http_request", b"http_request", "http_response_body", b"http_response_body", "http_response_start", b"http_response_start", "http_response_trailers", b"http_response_trailers", "type", b"type", "websock
  13. line length 606 characters (raw pass, confidence 0.50)

        def ClearField(self, field_name: typing_extensions.Literal["http", b"http", "http_disconnect", b"http_disconnect", "http_request", b"http_request", "http_response_body", b"http_response_body", "http_response_start", b"http_response_start", "http_response_trailers", b"http_response_trailers", "type", b"type", "webso
  14. line length 513 characters (raw pass, confidence 0.50)

        def ClearField(self, field_name: typing_extensions.Literal["_checkpoint_id", b"_checkpoint_id", "app_id", b"app_id", "app_layout", b"app_layout", "checkpoint_id", b"checkpoint_id", "environment_name", b"environment_name", "function_def", b"function_def", "function_id", b"function_id", "input_plane_server_url", b"in
  15. line length 537 characters (raw pass, confidence 0.50)

        def ClearField(self, field_name: typing_extensions.Literal["_recipe_id", b"_recipe_id", "api_surfaces", b"api_surfaces", "compute_region", b"compute_region", "description", b"description", "environment_name", b"environment_name", "input_modalities", b"input_modalities", "model", b"model", "name", b"name", "proxy_re
  16. line length 507 characters (raw pass, confidence 0.50)

        def ClearField(self, field_name: typing_extensions.Literal["active_deployment_id", b"active_deployment_id", "app_state", b"app_state", "created_by_avatar_url", b"created_by_avatar_url", "description", b"description", "endpoint_id", b"endpoint_id", "function_id", b"function_id", "metadata", b"metadata", "name", b"na
  17. line length 600 characters (raw pass, confidence 0.50)

            def ClearField(self, field_name: typing_extensions.Literal["_has_role_assignment", b"_has_role_assignment", "_inherits_default_member_role", b"_inherits_default_member_role", "avatar_url", b"avatar_url", "choosable_roles", b"choosable_roles", "email", b"email", "has_role_assignment", b"has_role_assignment", "in
  18. line length 504 characters (raw pass, confidence 0.50)

        def ClearField(self, field_name: typing_extensions.Literal["_block_unauthenticated_resources", b"_block_unauthenticated_resources", "_max_concurrent_gpus", b"_max_concurrent_gpus", "_max_concurrent_tasks", b"_max_concurrent_tasks", "block_unauthenticated_resources", b"block_unauthenticated_resources", "image_builde
  19. line length 744 characters (raw pass, confidence 0.50)

        def HasField(self, field_name: typing_extensions.Literal["_cloud_provider", b"_cloud_provider", "_http_config", b"_http_config", "_proxy_id", b"_proxy_id", "_scheduler_placement", b"_scheduler_placement", "autoscaler_settings", b"autoscaler_settings", "checkpoint", b"checkpoint", "class_parameter_info", b"class_par
  20. line length 546 characters (raw pass, confidence 0.50)

        def HasField(self, field_name: typing_extensions.Literal["_container_id", b"_container_id", "_execution_time_seconds", b"_execution_time_seconds", "_service_method_name", b"_service_method_name", "_started_at", b"_started_at", "_startup_time_seconds", b"_startup_time_seconds", "container_id", b"container_id", "enqu
  21. line length 601 characters (raw pass, confidence 0.50)

        def ClearField(self, field_name: typing_extensions.Literal["_container_id", b"_container_id", "_execution_time_seconds", b"_execution_time_seconds", "_service_method_name", b"_service_method_name", "_started_at", b"_started_at", "_startup_time_seconds", b"_startup_time_seconds", "container_id", b"container_id", "en
  22. line length 575 characters (raw pass, confidence 0.50)

        def HasField(self, field_name: typing_extensions.Literal["_input_plane_region", b"_input_plane_region", "_input_plane_url", b"_input_plane_url", "_max_async_object_size_bytes", b"_max_async_object_size_bytes", "_max_object_size_bytes", b"_max_object_size_bytes", "class_parameter_info", b"class_parameter_info", "fun
  23. line length 636 characters (raw pass, confidence 0.50)

        def ClearField(self, field_name: typing_extensions.Literal["arch", b"arch", "base_images", b"base_images", "build_args", b"build_args", "build_function", b"build_function", "build_function_def", b"build_function_def", "build_function_globals", b"build_function_globals", "context_files", b"context_files", "context_m
  24. line length 584 characters (raw pass, confidence 0.50)

        def ClearField(self, field_name: typing_extensions.Literal["_idle_timeout_secs", b"_idle_timeout_secs", "_readiness_probe", b"_readiness_probe", "_ready_at", b"_ready_at", "app_id", b"app_id", "created_at", b"created_at", "id", b"id", "idle_timeout_secs", b"idle_timeout_secs", "image_id", b"image_id", "metadata", b
  25. compression ratio 0.640 is >2σ above file mean 0.605 (raw pass, confidence 0.50)

        @abc.abstractmethod
        async def TaskExecWait(self, stream: 'grpclib.server.Stream[modal_proto.task_command_router_pb2.TaskExecWaitRequest, modal_proto.task_command_router_pb2.TaskExecWaitResponse]') -> None:
            pass
  26. line length 569 characters (raw pass, confidence 0.50)

        def ClearField(self, field_name: typing_extensions.Literal["_memory_reserve_consume_mib", b"_memory_reserve_consume_mib", "_network_access", b"_network_access", "_pty_info", b"_pty_info", "args", b"args", "container_name", b"container_name", "env", b"env", "image_id", b"image_id", "memory_reserve_consume_mib", b"me
  27. line length 542 characters (raw pass, confidence 0.50)

        def ClearField(self, field_name: typing_extensions.Literal["_pty_info", b"_pty_info", "_timeout_secs", b"_timeout_secs", "_workdir", b"_workdir", "command_args", b"command_args", "container_id", b"container_id", "env", b"env", "exec_id", b"exec_id", "pty_info", b"pty_info", "runtime_debug", b"runtime_debug", "secre

Reproduce This Scan

Run disclude locally to verify. These commands scan the published file; the "new in this release" marks come from comparing it with the previous release's file, which they don't repeat. Add --format sarif for SARIF output. Add --llm (with an API key in the environment) to include the LLM review.

cargo install disclude --version 4.3.0
curl -fsSL -o modal-1.6.3.dev1-py3-none-any.whl https://files.pythonhosted.org/packages/13/2c/dae6e397985c725644863b7b700c8415c724be7f825a4dc173335b0c10aa/modal-1.6.3.dev1-py3-none-any.whl
printf '%s  %s\n' 3746fc05d80a2a5746ca90053fde2fd8d3b7022bcaf9776420996a059a94c062 modal-1.6.3.dev1-py3-none-any.whl | shasum -a 256 -c -
unzip -q modal-1.6.3.dev1-py3-none-any.whl -d pkg
disclude scan --untrusted --severity info pkg