VYPR
High severityOSV Advisory· Published Jan 2, 2026· Updated Feb 26, 2026

Langflow Missing Authentication on Critical API Endpoints

CVE-2026-21445

Description

Langflow is a tool for building and deploying AI-powered agents and workflows. Prior to version 1.7.0.dev45, multiple critical API endpoints in Langflow are missing authentication controls. The issue allows any unauthenticated user to access sensitive user conversation data, transaction histories, and perform destructive operations including message deletion. This affects endpoints handling personal data and system operations that should require proper authorization. Version 1.7.0.dev45 contains a patch.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Multiple critical API endpoints in Langflow prior to 1.7.0.dev45 lack authentication, allowing unauthenticated access to sensitive conversation data, transaction histories, and message deletion.

Vulnerability

Overview

CVE-2026-21445 describes a missing authentication vulnerability in Langflow, a tool for building and deploying AI-powered agents and workflows. Prior to version 1.7.0.dev45, several critical API endpoints in the /api/v1/monitor route were not protected by the Depends(get_current_active_user) authentication dependency. This oversight allowed any unauthenticated user to access sensitive data and perform destructive operations [1][3].

Exploitation

Details

The affected endpoints include GET /api/v1/monitor/monitor/messages, GET /api/v1/monitor/transactions, and DELETE /api/v1/monitor/messages/session/{session_id}. These endpoints lack any authentication checks, meaning an attacker can send requests without providing any credentials or API keys. The vulnerability can be exploited remotely over the network, requiring no special privileges or user interaction. An attacker simply needs to know the base URL of a running Langflow instance's URL and can use tools like curl to access the endpoints [3].

Impact

Successful exploitation allows an unauthenticated attacker to read all user conversation data and transaction histories, which may contain sensitive personal information. Furthermore, the attacker can delete entire message sessions, causing data loss and potentially disrupting workflows. This represents a significant breach of confidentiality and integrity, as the endpoints handle personal data and system operations that should require proper authorization [2][3].

Mitigation

The vulnerability has been patched in Langflow version 1.7.0.dev45. The fix adds the missing authentication dependency to the affected endpoints, ensuring that only authenticated users can access them. Users are strongly advised to upgrade to the patched version immediately. No workarounds are mentioned in the advisories [1][2][3].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
langflow-basePyPI
< 0.7.10.7.1
langflowPyPI
< 1.7.11.7.1

Affected products

2
  • Langflow Ai/LangflowOSV2 versions
    1.1.2, 1.1.3, 1.1.4, …+ 1 more
    • (no CPE)range: 1.1.2, 1.1.3, 1.1.4, …
    • (no CPE)range: <1.7.0.dev45

Patches

1
3fed9fe1b565

fix: Add authentication to various endpoints (#10977)

https://github.com/langflow-ai/langflowEric HareDec 12, 2025via ghsa
16 files changed · +195 70
  • src/backend/base/langflow/api/log_router.py+10 3 modified
    @@ -3,10 +3,12 @@
     from http import HTTPStatus
     from typing import Annotated, Any
     
    -from fastapi import APIRouter, HTTPException, Query, Request
    +from fastapi import APIRouter, Depends, HTTPException, Query, Request
     from fastapi.responses import JSONResponse, StreamingResponse
     from lfx.log.logger import log_buffer
     
    +from langflow.services.auth.utils import get_current_active_user
    +
     log_router = APIRouter(tags=["Log"])
     
     
    @@ -50,12 +52,13 @@ async def event_generator(request: Request):
             await asyncio.sleep(1)
     
     
    -@log_router.get("/logs-stream")
    +@log_router.get("/logs-stream", dependencies=[Depends(get_current_active_user)])
     async def stream_logs(
         request: Request,
     ):
         """HTTP/2 Server-Sent-Event (SSE) endpoint for streaming logs.
     
    +    Requires authentication to prevent exposure of sensitive log data.
         It establishes a long-lived connection to the server and receives log messages in real-time.
         The client should use the header "Accept: text/event-stream".
         """
    @@ -69,12 +72,16 @@ async def stream_logs(
         return StreamingResponse(event_generator(request), media_type="text/event-stream")
     
     
    -@log_router.get("/logs")
    +@log_router.get("/logs", dependencies=[Depends(get_current_active_user)])
     async def logs(
         lines_before: Annotated[int, Query(description="The number of logs before the timestamp or the last log")] = 0,
         lines_after: Annotated[int, Query(description="The number of logs after the timestamp")] = 0,
         timestamp: Annotated[int, Query(description="The timestamp to start getting logs from")] = 0,
     ):
    +    """Retrieve application logs with authentication required.
    +
    +    SECURITY: Logs may contain sensitive information and require authentication.
    +    """
         global log_buffer  # noqa: PLW0602
         if log_buffer.enabled() is False:
             raise HTTPException(
    
  • src/backend/base/langflow/api/v1/chat.py+17 5 modified
    @@ -37,6 +37,7 @@
         VerticesOrderResponse,
     )
     from langflow.exceptions.component import ComponentBuildError
    +from langflow.services.auth.utils import get_current_active_user
     from langflow.services.chat.service import ChatService
     from langflow.services.database.models.flow.model import Flow
     from langflow.services.deps import (
    @@ -54,7 +55,7 @@
     router = APIRouter(tags=["Chat"])
     
     
    -@router.post("/build/{flow_id}/vertices", deprecated=True)
    +@router.post("/build/{flow_id}/vertices", deprecated=True, dependencies=[Depends(get_current_active_user)])
     async def retrieve_vertices_order(
         *,
         flow_id: uuid.UUID,
    @@ -197,27 +198,37 @@ async def build_flow(
         )
     
     
    -@router.get("/build/{job_id}/events")
    +@router.get("/build/{job_id}/events", dependencies=[Depends(get_current_active_user)])
     async def get_build_events(
         job_id: str,
         queue_service: Annotated[JobQueueService, Depends(get_queue_service)],
         *,
         event_delivery: EventDeliveryType = EventDeliveryType.STREAMING,
     ):
    -    """Get events for a specific build job."""
    +    """Get events for a specific build job.
    +
    +    Requires authentication to prevent unauthorized access to build events.
    +    """
         return await get_flow_events_response(
             job_id=job_id,
             queue_service=queue_service,
             event_delivery=event_delivery,
         )
     
     
    -@router.post("/build/{job_id}/cancel", response_model=CancelFlowResponse)
    +@router.post(
    +    "/build/{job_id}/cancel",
    +    response_model=CancelFlowResponse,
    +    dependencies=[Depends(get_current_active_user)],
    +)
     async def cancel_build(
         job_id: str,
         queue_service: Annotated[JobQueueService, Depends(get_queue_service)],
     ):
    -    """Cancel a specific build job."""
    +    """Cancel a specific build job.
    +
    +    Requires authentication to prevent unauthorized build cancellation.
    +    """
         try:
             # Cancel the flow build and check if it was successful
             cancellation_success = await cancel_flow_build(job_id=job_id, queue_service=queue_service)
    @@ -509,6 +520,7 @@ async def _stream_vertex(flow_id: str, vertex_id: str, chat_service: ChatService
         "/build/{flow_id}/{vertex_id}/stream",
         response_class=StreamingResponse,
         deprecated=True,
    +    dependencies=[Depends(get_current_active_user)],
     )
     async def build_vertex_stream(
         flow_id: uuid.UUID,
    
  • src/backend/base/langflow/api/v1/endpoints.py+3 1 modified
    @@ -961,10 +961,12 @@ async def custom_component_update(
             raise SerializationError.from_exception(exc, data=component_node) from exc
     
     
    -@router.get("/config")
    +@router.get("/config", dependencies=[Depends(get_current_active_user)])
     async def get_config() -> ConfigResponse:
         """Retrieve the current application configuration settings.
     
    +    Requires authentication to prevent exposure of sensitive configuration details.
    +
         Returns:
             ConfigResponse: The configuration settings of the application.
     
    
  • src/backend/base/langflow/api/v1/files.py+101 29 modified
    @@ -21,6 +21,41 @@
     router = APIRouter(tags=["Files"], prefix="/files")
     
     
    +def _get_allowed_profile_picture_folders(settings_service: SettingsService) -> set[str]:
    +    """Return the set of allowed profile picture folders.
    +
    +    This enumerates subdirectories under the profile_pictures directory in both
    +    the user's config_dir and the package's bundled assets. This makes the API
    +    flexible (users may add new folders under config_dir/profile_pictures) while
    +    still safe because we only ever serve files contained within the resolved
    +    base directory and validate path containment below.
    +
    +    If no directories can be found (unexpected), fall back to the curated
    +    defaults {"People", "Space"} shipped with Langflow.
    +    """
    +    allowed: set[str] = set()
    +    try:
    +        # Config-provided folders
    +        config_dir = Path(settings_service.settings.config_dir)
    +        cfg_base = config_dir / "profile_pictures"
    +        if cfg_base.exists():
    +            allowed.update({p.name for p in cfg_base.iterdir() if p.is_dir()})
    +        # Package-provided folders
    +        from langflow.initial_setup import setup
    +
    +        pkg_base = Path(setup.__file__).parent / "profile_pictures"
    +        if pkg_base.exists():
    +            allowed.update({p.name for p in pkg_base.iterdir() if p.is_dir()})
    +    except Exception as _:
    +        import logging
    +
    +        logger = logging.getLogger(__name__)
    +        logger.exception("Exception occurred while getting allowed profile picture folders")
    +
    +    # Sensible defaults ensure tests and OOTB behavior
    +    return allowed or {"People", "Space"}
    +
    +
     # Create dep that gets the flow_id from the request
     # then finds it in the database and returns it while
     # using the current user as the owner
    @@ -31,10 +66,9 @@ async def get_flow(
     ):
         # AttributeError: 'SelectOfScalar' object has no attribute 'first'
         flow = await session.get(Flow, flow_id)
    -    if not flow:
    +    # Return 404 for both non-existent flows and unauthorized access to prevent information disclosure
    +    if not flow or flow.user_id != current_user.id:
             raise HTTPException(status_code=404, detail="Flow not found")
    -    if flow.user_id != current_user.id:
    -        raise HTTPException(status_code=403, detail="You don't have access to this flow")
         return flow
     
     
    @@ -43,7 +77,6 @@ async def upload_file(
         *,
         file: UploadFile,
         flow: Annotated[Flow, Depends(get_flow)],
    -    current_user: CurrentActiveUser,
         storage_service: Annotated[StorageService, Depends(get_storage_service)],
         settings_service: Annotated[SettingsService, Depends(get_settings_service)],
     ) -> UploadFileResponse:
    @@ -57,9 +90,7 @@ async def upload_file(
                 status_code=413, detail=f"File size is larger than the maximum file size {max_file_size_upload}MB."
             )
     
    -    if flow.user_id != current_user.id:
    -        raise HTTPException(status_code=403, detail="You don't have access to this flow")
    -
    +    # Authorization handled by get_flow dependency
         try:
             file_content = await file.read()
             timestamp = datetime.now(tz=timezone.utc).astimezone().strftime("%Y-%m-%d_%H-%M-%S")
    @@ -74,9 +105,12 @@ async def upload_file(
     
     @router.get("/download/{flow_id}/{file_name}")
     async def download_file(
    -    file_name: str, flow_id: UUID, storage_service: Annotated[StorageService, Depends(get_storage_service)]
    +    file_name: str,
    +    flow: Annotated[Flow, Depends(get_flow)],
    +    storage_service: Annotated[StorageService, Depends(get_storage_service)],
     ):
    -    flow_id_str = str(flow_id)
    +    # Authorization handled by get_flow dependency
    +    flow_id_str = str(flow.id)
         extension = file_name.split(".")[-1]
     
         if not extension:
    @@ -102,10 +136,14 @@ async def download_file(
     
     
     @router.get("/images/{flow_id}/{file_name}")
    -async def download_image(file_name: str, flow_id: UUID):
    +async def download_image(
    +    file_name: str,
    +    flow: Annotated[Flow, Depends(get_flow)],
    +):
    +    # Authorization handled by get_flow dependency
         storage_service = get_storage_service()
         extension = file_name.split(".")[-1]
    -    flow_id_str = str(flow_id)
    +    flow_id_str = str(flow.id)
     
         if not extension:
             raise HTTPException(status_code=500, detail=f"Extension not found for file {file_name}")
    @@ -138,16 +176,49 @@ async def download_profile_picture(
         then fallback to the package's bundled profile_pictures directory.
         """
         try:
    +        # SECURITY: Validate inputs to prevent path traversal attacks
    +        # Reject any path components that contain directory traversal sequences
    +        if ".." in folder_name or ".." in file_name:
    +            raise HTTPException(
    +                status_code=400, detail="Path traversal patterns ('..') are not allowed in folder or file names"
    +            )
    +
    +        # Only allow specific folder names (dynamic from config + package)
    +        allowed_folders = _get_allowed_profile_picture_folders(settings_service)
    +        if folder_name not in allowed_folders:
    +            raise HTTPException(status_code=400, detail=f"Folder must be one of: {', '.join(sorted(allowed_folders))}")
    +
    +        # Validate file name contains no path separators
    +        if "/" in file_name or "\\" in file_name:
    +            raise HTTPException(status_code=400, detail="File name cannot contain path separators ('/' or '\\')")
    +
             extension = file_name.split(".")[-1]
             config_dir = settings_service.settings.config_dir
    -        config_path = Path(config_dir)  # type: ignore[arg-type]
    -        file_path = config_path / "profile_pictures" / folder_name / file_name
    +        config_path = Path(config_dir).resolve()  # type: ignore[arg-type]
    +
    +        # Construct the file path
    +        file_path = (config_path / "profile_pictures" / folder_name / file_name).resolve()
    +
    +        # SECURITY: Verify the resolved path is still within the allowed directory
    +        # This prevents path traversal even if symbolic links are involved
    +        allowed_base = (config_path / "profile_pictures").resolve()
    +        if not str(file_path).startswith(str(allowed_base)):
    +            # Return 404 to prevent path traversal attempts from revealing system structure
    +            raise HTTPException(status_code=404, detail="Profile picture not found")
     
             # Fallback to package bundled profile pictures if not found in config_dir
             if not file_path.exists():
                 from langflow.initial_setup import setup
     
    -            package_path = Path(setup.__file__).parent / "profile_pictures" / folder_name / file_name
    +            package_base = Path(setup.__file__).parent / "profile_pictures"
    +            package_path = (package_base / folder_name / file_name).resolve()
    +
    +            # SECURITY: Verify package path is also within allowed directory
    +            allowed_package_base = package_base.resolve()
    +            if not str(package_path).startswith(str(allowed_package_base)):
    +                # Return 404 to prevent path traversal attempts from revealing system structure
    +                raise HTTPException(status_code=404, detail="Profile picture not found")
    +
                 if package_path.exists():
                     file_path = package_path
                 else:
    @@ -177,29 +248,30 @@ async def list_profile_pictures(
             config_dir = settings_service.settings.config_dir
             config_path = Path(config_dir)  # type: ignore[arg-type]
     
    -        people_path = config_path / "profile_pictures" / "People"
    -        space_path = config_path / "profile_pictures" / "Space"
    +        # Build list for all allowed folders (dynamic)
    +        allowed_folders = _get_allowed_profile_picture_folders(settings_service)
     
    -        # List files directly from local filesystem
    -        people = [f.name for f in people_path.iterdir() if f.is_file()] if people_path.exists() else []
    -        space = [f.name for f in space_path.iterdir() if f.is_file()] if space_path.exists() else []
    +        results: list[str] = []
    +        cfg_base = config_path / "profile_pictures"
    +        if cfg_base.exists():
    +            for folder in sorted(allowed_folders):
    +                p = cfg_base / folder
    +                if p.exists():
    +                    results += [f"{folder}/{f.name}" for f in p.iterdir() if f.is_file()]
     
    -        # Fallback to package bundled profile pictures if config_dir is empty
    -        if not people and not space:
    +        # Fallback to package if config_dir produced no results
    +        if not results:
                 from langflow.initial_setup import setup
     
                 package_base = Path(setup.__file__).parent / "profile_pictures"
    -            people_path = package_base / "People"
    -            space_path = package_base / "Space"
    -            people = [f.name for f in people_path.iterdir() if f.is_file()] if people_path.exists() else []
    -            space = [f.name for f in space_path.iterdir() if f.is_file()] if space_path.exists() else []
    +            for folder in sorted(allowed_folders):
    +                p = package_base / folder
    +                if p.exists():
    +                    results += [f"{folder}/{f.name}" for f in p.iterdir() if f.is_file()]
         except Exception as e:
             raise HTTPException(status_code=500, detail=str(e)) from e
     
    -    files = [f"People/{i}" for i in people]
    -    files += [f"Space/{i}" for i in space]
    -
    -    return {"files": files}
    +    return {"files": results}
     
     
     @router.get("/list/{flow_id}")
    
  • src/backend/base/langflow/api/v1/models.py+3 2 modified
    @@ -4,7 +4,7 @@
     import logging
     from typing import Annotated
     
    -from fastapi import APIRouter, HTTPException, Query
    +from fastapi import APIRouter, Depends, HTTPException, Query
     from lfx.base.models.unified_models import (
         get_model_provider_variable_mapping,
         get_model_providers,
    @@ -13,6 +13,7 @@
     from pydantic import BaseModel, field_validator
     
     from langflow.api.utils import CurrentActiveUser, DbSession
    +from langflow.services.auth.utils import get_current_active_user
     from langflow.services.deps import get_variable_service
     from langflow.services.variable.constants import CREDENTIAL_TYPE, GENERIC_TYPE
     from langflow.services.variable.service import DatabaseVariableService
    @@ -93,7 +94,7 @@ def validate_non_empty_string(cls, v: str) -> str:
             return v.strip()
     
     
    -@router.get("/providers", status_code=200)
    +@router.get("/providers", status_code=200, dependencies=[Depends(get_current_active_user)])
     async def list_model_providers() -> list[str]:
         """Return available model providers."""
         return get_model_providers()
    
  • src/backend/base/langflow/api/v1/monitor.py+2 2 modified
    @@ -22,7 +22,7 @@
     router = APIRouter(prefix="/monitor", tags=["Monitor"])
     
     
    -@router.get("/builds")
    +@router.get("/builds", dependencies=[Depends(get_current_active_user)])
     async def get_vertex_builds(flow_id: Annotated[UUID, Query()], session: DbSession) -> VertexBuildMapModel:
         try:
             vertex_builds = await get_vertex_builds_by_flow_id(session, flow_id)
    @@ -31,7 +31,7 @@ async def get_vertex_builds(flow_id: Annotated[UUID, Query()], session: DbSessio
             raise HTTPException(status_code=500, detail=str(e)) from e
     
     
    -@router.delete("/builds", status_code=204)
    +@router.delete("/builds", status_code=204, dependencies=[Depends(get_current_active_user)])
     async def delete_vertex_builds(flow_id: Annotated[UUID, Query()], session: DbSession) -> None:
         try:
             await delete_vertex_builds_by_flow_id(session, flow_id)
    
  • src/backend/base/langflow/api/v1/users.py+5 1 modified
    @@ -26,8 +26,12 @@
     async def add_user(
         user: UserCreate,
         session: DbSession,
    +    current_user: Annotated[User, Depends(get_current_active_superuser)],  # noqa: ARG001
     ) -> User:
    -    """Add a new user to the database."""
    +    """Add a new user to the database.
    +
    +    Requires superuser authentication to prevent unauthorized account creation.
    +    """
         new_user = User.model_validate(user, from_attributes=True)
         try:
             new_user.password = get_password_hash(user.password)
    
  • src/backend/base/langflow/api/v1/validate.py+8 6 modified
    @@ -1,17 +1,17 @@
    -from fastapi import APIRouter, HTTPException
    +from fastapi import APIRouter, Depends, HTTPException
     from lfx.base.prompts.api_utils import process_prompt_template
     from lfx.custom.validate import validate_code
     from lfx.log.logger import logger
     
    -from langflow.api.utils import CurrentActiveUser
     from langflow.api.v1.base import Code, CodeValidationResponse, PromptValidationResponse, ValidatePromptRequest
    +from langflow.services.auth.utils import get_current_active_user
     
     # build router
     router = APIRouter(prefix="/validate", tags=["Validate"])
     
     
    -@router.post("/code", status_code=200)
    -async def post_validate_code(code: Code, _current_user: CurrentActiveUser) -> CodeValidationResponse:
    +@router.post("/code", status_code=200, dependencies=[Depends(get_current_active_user)])
    +async def post_validate_code(code: Code) -> CodeValidationResponse:
         try:
             errors = validate_code(code.code)
             return CodeValidationResponse(
    @@ -23,8 +23,10 @@ async def post_validate_code(code: Code, _current_user: CurrentActiveUser) -> Co
             raise HTTPException(status_code=500, detail=str(e)) from e
     
     
    -@router.post("/prompt", status_code=200)
    -async def post_validate_prompt(prompt_request: ValidatePromptRequest) -> PromptValidationResponse:
    +@router.post("/prompt", status_code=200, dependencies=[Depends(get_current_active_user)])
    +async def post_validate_prompt(
    +    prompt_request: ValidatePromptRequest,
    +) -> PromptValidationResponse:
         try:
             if not prompt_request.frontend_node:
                 return PromptValidationResponse(
    
  • src/backend/base/langflow/api/v2/files.py+4 3 modified
    @@ -98,7 +98,8 @@ async def fetch_file_object(file_id: uuid.UUID, current_user: CurrentActiveUser,
     
         # Make sure the user has access to the file
         if file.user_id != current_user.id:
    -        raise HTTPException(status_code=403, detail="You don't have access to this file")
    +        # Return 404 to prevent information disclosure about resource existence
    +        raise HTTPException(status_code=404, detail="File not found")
     
         return file
     
    @@ -225,8 +226,8 @@ async def upload_user_file(
                 # S3 bucket doesn't exist or file not found, or file was uploaded but can't be found
                 raise HTTPException(status_code=404, detail=str(e)) from e
             except PermissionError as e:
    -            # Access denied or invalid credentials
    -            raise HTTPException(status_code=403, detail=str(e)) from e
    +            # Access denied or invalid credentials - return 500 as this is a server config issue
    +            raise HTTPException(status_code=500, detail="Error accessing storage") from e
             except Exception as e:
                 # General error saving file or getting file size
                 raise HTTPException(status_code=500, detail=f"Error accessing file: {e}") from e
    
  • src/backend/base/langflow/api/v2/registration.py+3 2 modified
    @@ -3,10 +3,11 @@
     from datetime import datetime, timezone
     from pathlib import Path
     
    -from fastapi import APIRouter, HTTPException
    +from fastapi import APIRouter, Depends, HTTPException
     from pydantic import BaseModel, EmailStr
     
     from langflow.logging import logger
    +from langflow.services.auth.utils import get_current_active_user
     from langflow.services.deps import get_telemetry_service
     from langflow.services.telemetry.schema import EmailPayload
     
    @@ -135,7 +136,7 @@ async def _send_email_telemetry(email: str) -> None:
         logger.debug(f"Successfully sent email telemetry event: {payload.email}")
     
     
    -@router.get("/")
    +@router.get("/", dependencies=[Depends(get_current_active_user)])
     async def get_registration():
         """Get the registered user (if any)."""
         try:
    
  • src/backend/tests/unit/api/v1/test_endpoints.py+2 2 modified
    @@ -21,8 +21,8 @@ async def test_get_version(client: AsyncClient):
         assert "package" in result, "The dictionary must contain a key called 'package'"
     
     
    -async def test_get_config(client: AsyncClient):
    -    response = await client.get("api/v1/config")
    +async def test_get_config(client: AsyncClient, logged_in_headers: dict):
    +    response = await client.get("api/v1/config", headers=logged_in_headers)
         result = response.json()
     
         assert response.status_code == status.HTTP_200_OK
    
  • src/backend/tests/unit/api/v1/test_files.py+6 4 modified
    @@ -576,15 +576,17 @@ async def test_download_profile_picture_not_found_in_both_locations(empty_config
     
     
     async def test_download_profile_picture_invalid_folder(empty_config_dir, files_client):  # noqa: ARG001
    -    """Test 404 when using an invalid folder name.
    +    """Test 400 when using an invalid folder name.
     
    -    Only 'People' and 'Space' folders should exist in the package.
    +    Only 'People' and 'Space' folders are whitelisted for security.
    +    Invalid folder names should be rejected with 400 Bad Request.
         """
         response = await files_client.get("api/v1/files/profile_pictures/InvalidFolder/file.svg")
    -    assert response.status_code == 404
    +    assert response.status_code == 400
     
         data = response.json()
    -    assert "not found" in data["detail"].lower()
    +    # Check for the new specific error message
    +    assert "folder must be one of" in data["detail"].lower()
     
     
     async def test_download_profile_picture_config_dir_takes_precedence(setup_profile_pictures, files_client):
    
  • src/backend/tests/unit/api/v1/test_users.py+4 4 modified
    @@ -2,9 +2,9 @@
     from httpx import AsyncClient
     
     
    -async def test_add_user(client: AsyncClient):
    +async def test_add_user(client: AsyncClient, logged_in_headers_super_user):
         basic_case = {"username": "string", "password": "string"}
    -    response = await client.post("api/v1/users/", json=basic_case)
    +    response = await client.post("api/v1/users/", json=basic_case, headers=logged_in_headers_super_user)
         result = response.json()
     
         assert response.status_code == status.HTTP_201_CREATED
    @@ -49,7 +49,7 @@ async def test_patch_user(client: AsyncClient, logged_in_headers_super_user):
         name = "string"
         updated_name = "string2"
         basic_case = {"username": name, "password": "string"}
    -    response_ = await client.post("api/v1/users/", json=basic_case)
    +    response_ = await client.post("api/v1/users/", json=basic_case, headers=logged_in_headers_super_user)
         id_ = response_.json()["id"]
         basic_case["username"] = updated_name
         response = await client.patch(f"api/v1/users/{id_}", json=basic_case, headers=logged_in_headers_super_user)
    @@ -88,7 +88,7 @@ async def test_reset_password(client: AsyncClient, logged_in_headers, active_use
     
     async def test_delete_user(client: AsyncClient, logged_in_headers_super_user):
         basic_case = {"username": "string", "password": "string"}
    -    response_ = await client.post("api/v1/users/", json=basic_case)
    +    response_ = await client.post("api/v1/users/", json=basic_case, headers=logged_in_headers_super_user)
         id_ = response_.json()["id"]
         response = await client.delete(f"api/v1/users/{id_}", headers=logged_in_headers_super_user)
         result = response.json()
    
  • src/backend/tests/unit/api/v2/test_registration.py+20 0 modified
    @@ -251,9 +251,14 @@ async def test_get_registration_exists(self, mock_load):
     
             from fastapi import FastAPI
             from fastapi.testclient import TestClient
    +        from langflow.services.auth.utils import get_current_active_user
     
             app = FastAPI()
             app.include_router(router)
    +
    +        # Override auth dependency to bypass authentication
    +        app.dependency_overrides[get_current_active_user] = lambda: MagicMock()
    +
             client = TestClient(app)
     
             response = client.get("/registration/")  # Fixed: Added /registration prefix
    @@ -271,9 +276,14 @@ async def test_get_registration_not_exists(self, mock_load):
     
             from fastapi import FastAPI
             from fastapi.testclient import TestClient
    +        from langflow.services.auth.utils import get_current_active_user
     
             app = FastAPI()
             app.include_router(router)
    +
    +        # Override auth dependency to bypass authentication
    +        app.dependency_overrides[get_current_active_user] = lambda: MagicMock()
    +
             client = TestClient(app)
     
             response = client.get("/registration/")  # Fixed: Added /registration prefix
    @@ -289,9 +299,14 @@ async def test_get_registration_error(self, mock_load):
     
             from fastapi import FastAPI
             from fastapi.testclient import TestClient
    +        from langflow.services.auth.utils import get_current_active_user
     
             app = FastAPI()
             app.include_router(router)
    +
    +        # Override auth dependency to bypass authentication
    +        app.dependency_overrides[get_current_active_user] = lambda: MagicMock()
    +
             client = TestClient(app)
     
             response = client.get("/registration/")  # Fixed: Added /registration prefix
    @@ -328,13 +343,18 @@ async def test_api_integration(self, tmp_path, monkeypatch):
             """Test API endpoints with actual file operations."""
             from fastapi import FastAPI
             from fastapi.testclient import TestClient
    +        from langflow.services.auth.utils import get_current_active_user
     
             # Set up temporary file path
             test_file = tmp_path / "registration.json"
             monkeypatch.setattr("langflow.api.v2.registration.REGISTRATION_FILE", test_file)
     
             app = FastAPI()
             app.include_router(router)
    +
    +        # Override auth dependency to bypass authentication
    +        app.dependency_overrides[get_current_active_user] = lambda: MagicMock()
    +
             client = TestClient(app)
     
             # Test registration
    
  • src/backend/tests/unit/test_endpoints.py+6 5 modified
    @@ -231,18 +231,19 @@ def square(x)
     INVALID_PROMPT = "This is an invalid prompt without any input variable."
     
     
    -async def test_valid_prompt(client: AsyncClient):
    +async def test_valid_prompt(client: AsyncClient, logged_in_headers):
         PROMPT_REQUEST["template"] = VALID_PROMPT
    -    response = await client.post("api/v1/validate/prompt", json=PROMPT_REQUEST)
    +    response = await client.post("api/v1/validate/prompt", json=PROMPT_REQUEST, headers=logged_in_headers)
         assert response.status_code == 200
         assert response.json()["input_variables"] == ["product"]
     
     
    -async def test_invalid_prompt(client: AsyncClient):
    +async def test_invalid_prompt(client: AsyncClient, logged_in_headers):
         PROMPT_REQUEST["template"] = INVALID_PROMPT
         response = await client.post(
             "api/v1/validate/prompt",
             json=PROMPT_REQUEST,
    +        headers=logged_in_headers,
         )
         assert response.status_code == 200
         assert response.json()["input_variables"] == []
    @@ -257,9 +258,9 @@ async def test_invalid_prompt(client: AsyncClient):
             ("{a}, {b}, and {c} are variables.", ["a", "b", "c"]),
         ],
     )
    -async def test_various_prompts(client, prompt, expected_input_variables):
    +async def test_various_prompts(client, logged_in_headers, prompt, expected_input_variables):
         PROMPT_REQUEST["template"] = prompt
    -    response = await client.post("api/v1/validate/prompt", json=PROMPT_REQUEST)
    +    response = await client.post("api/v1/validate/prompt", json=PROMPT_REQUEST, headers=logged_in_headers)
         assert response.status_code == 200
         assert response.json()["input_variables"] == expected_input_variables
     
    
  • src/lfx/src/lfx/_assets/component_index.json+1 1 modified

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.