gpt_academic provides a graphical interface for ChatGPT/GLM. A vulnerability was found in gpt_academic 3.37 and prior. This issue affects some unknown processing of the component Configuration File Handler. The manipulation of the argument file leads to information disclosure. Since no sensitive files are configured to be off-limits, sensitive information files in some working directories can be read through the `/file` route, leading to sensitive information leakage. This affects users that uses file configurations via `config.py`, `config_private.py`, `Dockerfile`. A patch is available at commit 1dcc2873d2168ad2d3d70afcb453ac1695fbdf02. As a workaround, one may use environment variables instead of `config*.py` files to configure this project, or use docker-compose installation to configure this project.

def main():
    import gradio as gr
    if gr.__version__ not in ['3.28.3','3.32.2']: assert False, "\u8bf7\u7528 pip install -r requirements.txt \u5b89\u88c5\u4f9d\u8d56"
    from request_llm.bridge_all import predict
    from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, DummyWith
    # \u5efa\u8bae\u60a8\u590d\u5236\u4e00\u4e2aconfig_private.py\u653e\u81ea\u5df1\u7684\u79d8\u5bc6, \u5982API\u548c\u4ee3\u7406\u7f51\u5740, \u907f\u514d\u4e0d\u5c0f\u5fc3\u4f20github\u88ab\u522b\u4eba\u770b\u5230
    proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION, CHATBOT_HEIGHT, LAYOUT, API_KEY, AVAIL_LLM_MODELS = \
        get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION', 'CHATBOT_HEIGHT', 'LAYOUT', 'API_KEY', 'AVAIL_LLM_MODELS')

    # \u5982\u679cWEB_PORT\u662f-1, \u5219\u968f\u673a\u9009\u53d6WEB\u7aef\u53e3
    PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
    if not AUTHENTICATION: AUTHENTICATION = None

    from check_proxy import get_current_version
    initial_prompt = "Serve me as a writing and programming assistant."
    title_html = f"
ChatGPT \u5b66\u672f\u4f18\u5316 {get_current_version()}
"
    description =  """\u4ee3\u7801\u5f00\u6e90\u548c\u66f4\u65b0[\u5730\u5740\ud83d\ude80](https://github.com/binary-husky/chatgpt_academic)\uff0c\u611f\u8c22\u70ed\u60c5\u7684[\u5f00\u53d1\u8005\u4eec\u2764\ufe0f](https://github.com/binary-husky/chatgpt_academic/graphs/contributors)"""

    # \u95ee\u8be2\u8bb0\u5f55, python \u7248\u672c\u5efa\u8bae3.9+\uff08\u8d8a\u65b0\u8d8a\u597d\uff09
    import logging
    os.makedirs("gpt_log", exist_ok=True)
    try:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO, encoding="utf-8")
    except:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO)
    print("\u6240\u6709\u95ee\u8be2\u8bb0\u5f55\u5c06\u81ea\u52a8\u4fdd\u5b58\u5728\u672c\u5730\u76ee\u5f55./gpt_log/chat_secrets.log, \u8bf7\u6ce8\u610f\u81ea\u6211\u9690\u79c1\u4fdd\u62a4\u54e6\uff01")

    # \u4e00\u4e9b\u666e\u901a\u529f\u80fd\u6a21\u5757
    from core_functional import get_core_functions
    functional = get_core_functions()

    # \u9ad8\u7ea7\u51fd\u6570\u63d2\u4ef6
    from crazy_functional import get_crazy_functions
    crazy_fns = get_crazy_functions()

    # \u5904\u7406markdown\u6587\u672c\u683c\u5f0f\u7684\u8f6c\u53d8
    gr.Chatbot.postprocess = format_io

    # \u505a\u4e00\u4e9b\u5916\u89c2\u8272\u5f69\u4e0a\u7684\u8c03\u6574
    from theme import adjust_theme, advanced_css
    set_theme = adjust_theme()

    # \u4ee3\u7406\u4e0e\u81ea\u52a8\u66f4\u65b0
    from check_proxy import check_proxy, auto_update, warm_up_modules
    proxy_info = check_proxy(proxies)

    gr_L1 = lambda: gr.Row().style()
    gr_L2 = lambda scale: gr.Column(scale=scale)
    if LAYOUT == "TOP-DOWN":
        gr_L1 = lambda: DummyWith()
        gr_L2 = lambda scale: gr.Row()
        CHATBOT_HEIGHT /= 2

    cancel_handles = []
    with gr.Blocks(title="ChatGPT \u5b66\u672f\u4f18\u5316", theme=set_theme, analytics_enabled=False, css=advanced_css) as demo:
        gr.HTML(title_html)
        cookies = gr.State({'api_key': API_KEY, 'llm_model': LLM_MODEL})
        with gr_L1():
            with gr_L2(scale=2):
                chatbot = gr.Chatbot(label=f"\u5f53\u524d\u6a21\u578b\uff1a{LLM_MODEL}")
                chatbot.style(height=CHATBOT_HEIGHT)
                history = gr.State([])
            with gr_L2(scale=1):
                with gr.Accordion("\u8f93\u5165\u533a", open=True) as area_input_primary:
                    with gr.Row():
                        txt = gr.Textbox(show_label=False, placeholder="Input question here.").style(container=False)
                    with gr.Row():
                        submitBtn = gr.Button("\u63d0\u4ea4", variant="primary")
                    with gr.Row():
                        resetBtn = gr.Button("\u91cd\u7f6e", variant="secondary"); resetBtn.style(size="sm")
                        stopBtn = gr.Button("\u505c\u6b62", variant="secondary"); stopBtn.style(size="sm")
                        clearBtn = gr.Button("\u6e05\u9664", variant="secondary", visible=False); clearBtn.style(size="sm")
                    with gr.Row():
                        status = gr.Markdown(f"Tip: \u6309Enter\u63d0\u4ea4, \u6309Shift+Enter\u6362\u884c\u3002\u5f53\u524d\u6a21\u578b: {LLM_MODEL} \n {proxy_info}")
                with gr.Accordion("\u57fa\u7840\u529f\u80fd\u533a", open=True) as area_basic_fn:
                    with gr.Row():
                        for k in functional:
                            if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
                            variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
                            functional[k]["Button"] = gr.Button(k, variant=variant)
                with gr.Accordion("\u51fd\u6570\u63d2\u4ef6\u533a", open=True) as area_crazy_fn:
                    with gr.Row():
                        gr.Markdown("\u6ce8\u610f\uff1a\u4ee5\u4e0b\u201c\u7ea2\u989c\u8272\u201d\u6807\u8bc6\u7684\u51fd\u6570\u63d2\u4ef6\u9700\u4ece\u8f93\u5165\u533a\u8bfb\u53d6\u8def\u5f84\u4f5c\u4e3a\u53c2\u6570.")
                    with gr.Row():
                        for k in crazy_fns:
                            if not crazy_fns[k].get("AsButton", True): continue
                            variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
                            crazy_fns[k]["Button"] = gr.Button(k, variant=variant)
                            crazy_fns[k]["Button"].style(size="sm")
                    with gr.Row():
                        with gr.Accordion("\u66f4\u591a\u51fd\u6570\u63d2\u4ef6", open=True):
                            dropdown_fn_list = [k for k in crazy_fns.keys() if not crazy_fns[k].get("AsButton", True)]
                            with gr.Row():
                                dropdown = gr.Dropdown(dropdown_fn_list, value=r"\u6253\u5f00\u63d2\u4ef6\u5217\u8868", label="").style(container=False)
                            with gr.Row():
                                plugin_advanced_arg = gr.Textbox(show_label=True, label="\u9ad8\u7ea7\u53c2\u6570\u8f93\u5165\u533a", visible=False,
                                                                 placeholder="\u8fd9\u91cc\u662f\u7279\u6b8a\u51fd\u6570\u63d2\u4ef6\u7684\u9ad8\u7ea7\u53c2\u6570\u8f93\u5165\u533a").style(container=False)
                            with gr.Row():
                                switchy_bt = gr.Button(r"\u8bf7\u5148\u4ece\u63d2\u4ef6\u5217\u8868\u4e2d\u9009\u62e9", variant="secondary")
                    with gr.Row():
                        with gr.Accordion("\u70b9\u51fb\u5c55\u5f00\u201c\u6587\u4ef6\u4e0a\u4f20\u533a\u201d\u3002\u4e0a\u4f20\u672c\u5730\u6587\u4ef6\u53ef\u4f9b\u7ea2\u8272\u51fd\u6570\u63d2\u4ef6\u8c03\u7528\u3002", open=False) as area_file_up:
                            file_upload = gr.Files(label="\u4efb\u4f55\u6587\u4ef6, \u4f46\u63a8\u8350\u4e0a\u4f20\u538b\u7f29\u6587\u4ef6(zip, tar)", file_count="multiple")
                with gr.Accordion("\u66f4\u6362\u6a21\u578b & SysPrompt & \u4ea4\u4e92\u754c\u9762\u5e03\u5c40", open=(LAYOUT == "TOP-DOWN")):
                    system_prompt = gr.Textbox(show_label=True, placeholder=f"System Prompt", label="System prompt", value=initial_prompt)
                    top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
                    temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
                    max_length_sl = gr.Slider(minimum=256, maximum=4096, value=512, step=1, interactive=True, label="Local LLM MaxLength",)
                    checkboxes = gr.CheckboxGroup(["\u57fa\u7840\u529f\u80fd\u533a", "\u51fd\u6570\u63d2\u4ef6\u533a", "\u5e95\u90e8\u8f93\u5165\u533a", "\u8f93\u5165\u6e05\u9664\u952e", "\u63d2\u4ef6\u53c2\u6570\u533a"], value=["\u57fa\u7840\u529f\u80fd\u533a", "\u51fd\u6570\u63d2\u4ef6\u533a"], label="\u663e\u793a/\u9690\u85cf\u529f\u80fd\u533a")
                    md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="\u66f4\u6362LLM\u6a21\u578b/\u8bf7\u6c42\u6e90").style(container=False)

                    gr.Markdown(description)
                with gr.Accordion("\u5907\u9009\u8f93\u5165\u533a", open=True, visible=False) as area_input_secondary:
                    with gr.Row():
                        txt2 = gr.Textbox(show_label=False, placeholder="Input question here.", label="\u8f93\u5165\u533a2").style(container=False)
                    with gr.Row():
                        submitBtn2 = gr.Button("\u63d0\u4ea4", variant="primary")
                    with gr.Row():
                        resetBtn2 = gr.Button("\u91cd\u7f6e", variant="secondary"); resetBtn2.style(size="sm")
                        stopBtn2 = gr.Button("\u505c\u6b62", variant="secondary"); stopBtn2.style(size="sm")
                        clearBtn2 = gr.Button("\u6e05\u9664", variant="secondary", visible=False); clearBtn2.style(size="sm")
        # \u529f\u80fd\u533a\u663e\u793a\u5f00\u5173\u4e0e\u529f\u80fd\u533a\u7684\u4e92\u52a8
        def fn_area_visibility(a):
            ret = {}
            ret.update({area_basic_fn: gr.update(visible=("\u57fa\u7840\u529f\u80fd\u533a" in a))})
            ret.update({area_crazy_fn: gr.update(visible=("\u51fd\u6570\u63d2\u4ef6\u533a" in a))})
            ret.update({area_input_primary: gr.update(visible=("\u5e95\u90e8\u8f93\u5165\u533a" not in a))})
            ret.update({area_input_secondary: gr.update(visible=("\u5e95\u90e8\u8f93\u5165\u533a" in a))})
            ret.update({clearBtn: gr.update(visible=("\u8f93\u5165\u6e05\u9664\u952e" in a))})
            ret.update({clearBtn2: gr.update(visible=("\u8f93\u5165\u6e05\u9664\u952e" in a))})
            ret.update({plugin_advanced_arg: gr.update(visible=("\u63d2\u4ef6\u53c2\u6570\u533a" in a))})
            if "\u5e95\u90e8\u8f93\u5165\u533a" in a: ret.update({txt: gr.update(value="")})
            return ret
        checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn, area_input_primary, area_input_secondary, txt, txt2, clearBtn, clearBtn2, plugin_advanced_arg] )
        # \u6574\u7406\u53cd\u590d\u51fa\u73b0\u7684\u63a7\u4ef6\u53e5\u67c4\u7ec4\u5408
        input_combo = [cookies, max_length_sl, md_dropdown, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg]
        output_combo = [cookies, chatbot, history, status]
        predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=input_combo, outputs=output_combo)
        # \u63d0\u4ea4\u6309\u94ae\u3001\u91cd\u7f6e\u6309\u94ae
        cancel_handles.append(txt.submit(**predict_args))
        cancel_handles.append(txt2.submit(**predict_args))
        cancel_handles.append(submitBtn.click(**predict_args))
        cancel_handles.append(submitBtn2.click(**predict_args))
        resetBtn.click(lambda: ([], [], "\u5df2\u91cd\u7f6e"), None, [chatbot, history, status])
        resetBtn2.click(lambda: ([], [], "\u5df2\u91cd\u7f6e"), None, [chatbot, history, status])
        clearBtn.click(lambda: ("",""), None, [txt, txt2])
        clearBtn2.click(lambda: ("",""), None, [txt, txt2])
        # \u57fa\u7840\u529f\u80fd\u533a\u7684\u56de\u8c03\u51fd\u6570\u6ce8\u518c
        for k in functional:
            if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
            click_handle = functional[k]["Button"].click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(k)], outputs=output_combo)
            cancel_handles.append(click_handle)
        # \u6587\u4ef6\u4e0a\u4f20\u533a\uff0c\u63a5\u6536\u6587\u4ef6\u540e\u4e0echatbot\u7684\u4e92\u52a8
        file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes], [chatbot, txt, txt2])
        # \u51fd\u6570\u63d2\u4ef6-\u56fa\u5b9a\u6309\u94ae\u533a
        for k in crazy_fns:
            if not crazy_fns[k].get("AsButton", True): continue
            click_handle = crazy_fns[k]["Button"].click(ArgsGeneralWrapper(crazy_fns[k]["Function"]), [*input_combo, gr.State(PORT)], output_combo)
            click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
            cancel_handles.append(click_handle)
        # \u51fd\u6570\u63d2\u4ef6-\u4e0b\u62c9\u83dc\u5355\u4e0e\u968f\u53d8\u6309\u94ae\u7684\u4e92\u52a8
        def on_dropdown_changed(k):
            variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
            ret = {switchy_bt: gr.update(value=k, variant=variant)}
            if crazy_fns[k].get("AdvancedArgs", False): # \u662f\u5426\u5524\u8d77\u9ad8\u7ea7\u63d2\u4ef6\u53c2\u6570\u533a
                ret.update({plugin_advanced_arg: gr.update(visible=True,  label=f"\u63d2\u4ef6[{k}]\u7684\u9ad8\u7ea7\u53c2\u6570\u8bf4\u660e\uff1a" + crazy_fns[k].get("ArgsReminder", [f"\u6ca1\u6709\u63d0\u4f9b\u9ad8\u7ea7\u53c2\u6570\u529f\u80fd\u8bf4\u660e"]))})
            else:
                ret.update({plugin_advanced_arg: gr.update(visible=False, label=f"\u63d2\u4ef6[{k}]\u4e0d\u9700\u8981\u9ad8\u7ea7\u53c2\u6570\u3002")})
            return ret
        dropdown.select(on_dropdown_changed, [dropdown], [switchy_bt, plugin_advanced_arg] )
        def on_md_dropdown_changed(k):
            return {chatbot: gr.update(label="\u5f53\u524d\u6a21\u578b\uff1a"+k)}
        md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot] )
        # \u968f\u53d8\u6309\u94ae\u7684\u56de\u8c03\u51fd\u6570\u6ce8\u518c
        def route(k, *args, **kwargs):
            if k in [r"\u6253\u5f00\u63d2\u4ef6\u5217\u8868", r"\u8bf7\u5148\u4ece\u63d2\u4ef6\u5217\u8868\u4e2d\u9009\u62e9"]: return
            yield from ArgsGeneralWrapper(crazy_fns[k]["Function"])(*args, **kwargs)
        click_handle = switchy_bt.click(route,[switchy_bt, *input_combo, gr.State(PORT)], output_combo)
        click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
        cancel_handles.append(click_handle)
        # \u7ec8\u6b62\u6309\u94ae\u7684\u56de\u8c03\u51fd\u6570\u6ce8\u518c
        stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
        stopBtn2.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)

    # gradio\u7684inbrowser\u89e6\u53d1\u4e0d\u592a\u7a33\u5b9a\uff0c\u56de\u6eda\u4ee3\u7801\u5230\u539f\u59cb\u7684\u6d4f\u89c8\u5668\u6253\u5f00\u51fd\u6570
    def auto_opentab_delay():
        import threading, webbrowser, time
        print(f"\u5982\u679c\u6d4f\u89c8\u5668\u6ca1\u6709\u81ea\u52a8\u6253\u5f00\uff0c\u8bf7\u590d\u5236\u5e76\u8f6c\u5230\u4ee5\u4e0bURL\uff1a")
        print(f"\t\uff08\u4eae\u8272\u4e3b\u9898\uff09: http://localhost:{PORT}")
        print(f"\t\uff08\u6697\u8272\u4e3b\u9898\uff09: http://localhost:{PORT}/?__theme=dark")
        def open():
            time.sleep(2)       # \u6253\u5f00\u6d4f\u89c8\u5668
            DARK_MODE, = get_conf('DARK_MODE')
            if DARK_MODE: webbrowser.open_new_tab(f"http://localhost:{PORT}/?__theme=dark")
            else: webbrowser.open_new_tab(f"http://localhost:{PORT}")
        threading.Thread(target=open, name="open-browser", daemon=True).start()
        threading.Thread(target=auto_update, name="self-upgrade", daemon=True).start()
        threading.Thread(target=warm_up_modules, name="warm-up", daemon=True).start()

    auto_opentab_delay()
    demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION, favicon_path="docs/logo.png")

def main():
    import gradio as gr
    if gr.__version__ not in ['3.28.3','3.32.2']: assert False, "\u8bf7\u7528 pip install -r requirements.txt \u5b89\u88c5\u4f9d\u8d56"
    from request_llm.bridge_all import predict
    from toolbox import format_io, find_free_port, on_file_uploaded, on_report_generated, get_conf, ArgsGeneralWrapper, DummyWith
    # \u5efa\u8bae\u60a8\u590d\u5236\u4e00\u4e2aconfig_private.py\u653e\u81ea\u5df1\u7684\u79d8\u5bc6, \u5982API\u548c\u4ee3\u7406\u7f51\u5740, \u907f\u514d\u4e0d\u5c0f\u5fc3\u4f20github\u88ab\u522b\u4eba\u770b\u5230
    proxies, WEB_PORT, LLM_MODEL, CONCURRENT_COUNT, AUTHENTICATION, CHATBOT_HEIGHT, LAYOUT, API_KEY, AVAIL_LLM_MODELS = \
        get_conf('proxies', 'WEB_PORT', 'LLM_MODEL', 'CONCURRENT_COUNT', 'AUTHENTICATION', 'CHATBOT_HEIGHT', 'LAYOUT', 'API_KEY', 'AVAIL_LLM_MODELS')

    # \u5982\u679cWEB_PORT\u662f-1, \u5219\u968f\u673a\u9009\u53d6WEB\u7aef\u53e3
    PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
    if not AUTHENTICATION: AUTHENTICATION = None

    from check_proxy import get_current_version
    initial_prompt = "Serve me as a writing and programming assistant."
    title_html = f"
ChatGPT \u5b66\u672f\u4f18\u5316 {get_current_version()}
"
    description =  """\u4ee3\u7801\u5f00\u6e90\u548c\u66f4\u65b0[\u5730\u5740\ud83d\ude80](https://github.com/binary-husky/chatgpt_academic)\uff0c\u611f\u8c22\u70ed\u60c5\u7684[\u5f00\u53d1\u8005\u4eec\u2764\ufe0f](https://github.com/binary-husky/chatgpt_academic/graphs/contributors)"""

    # \u95ee\u8be2\u8bb0\u5f55, python \u7248\u672c\u5efa\u8bae3.9+\uff08\u8d8a\u65b0\u8d8a\u597d\uff09
    import logging
    os.makedirs("gpt_log", exist_ok=True)
    try:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO, encoding="utf-8")
    except:logging.basicConfig(filename="gpt_log/chat_secrets.log", level=logging.INFO)
    print("\u6240\u6709\u95ee\u8be2\u8bb0\u5f55\u5c06\u81ea\u52a8\u4fdd\u5b58\u5728\u672c\u5730\u76ee\u5f55./gpt_log/chat_secrets.log, \u8bf7\u6ce8\u610f\u81ea\u6211\u9690\u79c1\u4fdd\u62a4\u54e6\uff01")

    # \u4e00\u4e9b\u666e\u901a\u529f\u80fd\u6a21\u5757
    from core_functional import get_core_functions
    functional = get_core_functions()

    # \u9ad8\u7ea7\u51fd\u6570\u63d2\u4ef6
    from crazy_functional import get_crazy_functions
    crazy_fns = get_crazy_functions()

    # \u5904\u7406markdown\u6587\u672c\u683c\u5f0f\u7684\u8f6c\u53d8
    gr.Chatbot.postprocess = format_io

    # \u505a\u4e00\u4e9b\u5916\u89c2\u8272\u5f69\u4e0a\u7684\u8c03\u6574
    from theme import adjust_theme, advanced_css
    set_theme = adjust_theme()

    # \u4ee3\u7406\u4e0e\u81ea\u52a8\u66f4\u65b0
    from check_proxy import check_proxy, auto_update, warm_up_modules
    proxy_info = check_proxy(proxies)

    gr_L1 = lambda: gr.Row().style()
    gr_L2 = lambda scale: gr.Column(scale=scale)
    if LAYOUT == "TOP-DOWN":
        gr_L1 = lambda: DummyWith()
        gr_L2 = lambda scale: gr.Row()
        CHATBOT_HEIGHT /= 2

    cancel_handles = []
    with gr.Blocks(title="ChatGPT \u5b66\u672f\u4f18\u5316", theme=set_theme, analytics_enabled=False, css=advanced_css) as demo:
        gr.HTML(title_html)
        cookies = gr.State({'api_key': API_KEY, 'llm_model': LLM_MODEL})
        with gr_L1():
            with gr_L2(scale=2):
                chatbot = gr.Chatbot(label=f"\u5f53\u524d\u6a21\u578b\uff1a{LLM_MODEL}")
                chatbot.style(height=CHATBOT_HEIGHT)
                history = gr.State([])
            with gr_L2(scale=1):
                with gr.Accordion("\u8f93\u5165\u533a", open=True) as area_input_primary:
                    with gr.Row():
                        txt = gr.Textbox(show_label=False, placeholder="Input question here.").style(container=False)
                    with gr.Row():
                        submitBtn = gr.Button("\u63d0\u4ea4", variant="primary")
                    with gr.Row():
                        resetBtn = gr.Button("\u91cd\u7f6e", variant="secondary"); resetBtn.style(size="sm")
                        stopBtn = gr.Button("\u505c\u6b62", variant="secondary"); stopBtn.style(size="sm")
                        clearBtn = gr.Button("\u6e05\u9664", variant="secondary", visible=False); clearBtn.style(size="sm")
                    with gr.Row():
                        status = gr.Markdown(f"Tip: \u6309Enter\u63d0\u4ea4, \u6309Shift+Enter\u6362\u884c\u3002\u5f53\u524d\u6a21\u578b: {LLM_MODEL} \n {proxy_info}")
                with gr.Accordion("\u57fa\u7840\u529f\u80fd\u533a", open=True) as area_basic_fn:
                    with gr.Row():
                        for k in functional:
                            if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
                            variant = functional[k]["Color"] if "Color" in functional[k] else "secondary"
                            functional[k]["Button"] = gr.Button(k, variant=variant)
                with gr.Accordion("\u51fd\u6570\u63d2\u4ef6\u533a", open=True) as area_crazy_fn:
                    with gr.Row():
                        gr.Markdown("\u6ce8\u610f\uff1a\u4ee5\u4e0b\u201c\u7ea2\u989c\u8272\u201d\u6807\u8bc6\u7684\u51fd\u6570\u63d2\u4ef6\u9700\u4ece\u8f93\u5165\u533a\u8bfb\u53d6\u8def\u5f84\u4f5c\u4e3a\u53c2\u6570.")
                    with gr.Row():
                        for k in crazy_fns:
                            if not crazy_fns[k].get("AsButton", True): continue
                            variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
                            crazy_fns[k]["Button"] = gr.Button(k, variant=variant)
                            crazy_fns[k]["Button"].style(size="sm")
                    with gr.Row():
                        with gr.Accordion("\u66f4\u591a\u51fd\u6570\u63d2\u4ef6", open=True):
                            dropdown_fn_list = [k for k in crazy_fns.keys() if not crazy_fns[k].get("AsButton", True)]
                            with gr.Row():
                                dropdown = gr.Dropdown(dropdown_fn_list, value=r"\u6253\u5f00\u63d2\u4ef6\u5217\u8868", label="").style(container=False)
                            with gr.Row():
                                plugin_advanced_arg = gr.Textbox(show_label=True, label="\u9ad8\u7ea7\u53c2\u6570\u8f93\u5165\u533a", visible=False,
                                                                 placeholder="\u8fd9\u91cc\u662f\u7279\u6b8a\u51fd\u6570\u63d2\u4ef6\u7684\u9ad8\u7ea7\u53c2\u6570\u8f93\u5165\u533a").style(container=False)
                            with gr.Row():
                                switchy_bt = gr.Button(r"\u8bf7\u5148\u4ece\u63d2\u4ef6\u5217\u8868\u4e2d\u9009\u62e9", variant="secondary")
                    with gr.Row():
                        with gr.Accordion("\u70b9\u51fb\u5c55\u5f00\u201c\u6587\u4ef6\u4e0a\u4f20\u533a\u201d\u3002\u4e0a\u4f20\u672c\u5730\u6587\u4ef6\u53ef\u4f9b\u7ea2\u8272\u51fd\u6570\u63d2\u4ef6\u8c03\u7528\u3002", open=False) as area_file_up:
                            file_upload = gr.Files(label="\u4efb\u4f55\u6587\u4ef6, \u4f46\u63a8\u8350\u4e0a\u4f20\u538b\u7f29\u6587\u4ef6(zip, tar)", file_count="multiple")
                with gr.Accordion("\u66f4\u6362\u6a21\u578b & SysPrompt & \u4ea4\u4e92\u754c\u9762\u5e03\u5c40", open=(LAYOUT == "TOP-DOWN")):
                    system_prompt = gr.Textbox(show_label=True, placeholder=f"System Prompt", label="System prompt", value=initial_prompt)
                    top_p = gr.Slider(minimum=-0, maximum=1.0, value=1.0, step=0.01,interactive=True, label="Top-p (nucleus sampling)",)
                    temperature = gr.Slider(minimum=-0, maximum=2.0, value=1.0, step=0.01, interactive=True, label="Temperature",)
                    max_length_sl = gr.Slider(minimum=256, maximum=4096, value=512, step=1, interactive=True, label="Local LLM MaxLength",)
                    checkboxes = gr.CheckboxGroup(["\u57fa\u7840\u529f\u80fd\u533a", "\u51fd\u6570\u63d2\u4ef6\u533a", "\u5e95\u90e8\u8f93\u5165\u533a", "\u8f93\u5165\u6e05\u9664\u952e", "\u63d2\u4ef6\u53c2\u6570\u533a"], value=["\u57fa\u7840\u529f\u80fd\u533a", "\u51fd\u6570\u63d2\u4ef6\u533a"], label="\u663e\u793a/\u9690\u85cf\u529f\u80fd\u533a")
                    md_dropdown = gr.Dropdown(AVAIL_LLM_MODELS, value=LLM_MODEL, label="\u66f4\u6362LLM\u6a21\u578b/\u8bf7\u6c42\u6e90").style(container=False)

                    gr.Markdown(description)
                with gr.Accordion("\u5907\u9009\u8f93\u5165\u533a", open=True, visible=False) as area_input_secondary:
                    with gr.Row():
                        txt2 = gr.Textbox(show_label=False, placeholder="Input question here.", label="\u8f93\u5165\u533a2").style(container=False)
                    with gr.Row():
                        submitBtn2 = gr.Button("\u63d0\u4ea4", variant="primary")
                    with gr.Row():
                        resetBtn2 = gr.Button("\u91cd\u7f6e", variant="secondary"); resetBtn2.style(size="sm")
                        stopBtn2 = gr.Button("\u505c\u6b62", variant="secondary"); stopBtn2.style(size="sm")
                        clearBtn2 = gr.Button("\u6e05\u9664", variant="secondary", visible=False); clearBtn2.style(size="sm")
        # \u529f\u80fd\u533a\u663e\u793a\u5f00\u5173\u4e0e\u529f\u80fd\u533a\u7684\u4e92\u52a8
        def fn_area_visibility(a):
            ret = {}
            ret.update({area_basic_fn: gr.update(visible=("\u57fa\u7840\u529f\u80fd\u533a" in a))})
            ret.update({area_crazy_fn: gr.update(visible=("\u51fd\u6570\u63d2\u4ef6\u533a" in a))})
            ret.update({area_input_primary: gr.update(visible=("\u5e95\u90e8\u8f93\u5165\u533a" not in a))})
            ret.update({area_input_secondary: gr.update(visible=("\u5e95\u90e8\u8f93\u5165\u533a" in a))})
            ret.update({clearBtn: gr.update(visible=("\u8f93\u5165\u6e05\u9664\u952e" in a))})
            ret.update({clearBtn2: gr.update(visible=("\u8f93\u5165\u6e05\u9664\u952e" in a))})
            ret.update({plugin_advanced_arg: gr.update(visible=("\u63d2\u4ef6\u53c2\u6570\u533a" in a))})
            if "\u5e95\u90e8\u8f93\u5165\u533a" in a: ret.update({txt: gr.update(value="")})
            return ret
        checkboxes.select(fn_area_visibility, [checkboxes], [area_basic_fn, area_crazy_fn, area_input_primary, area_input_secondary, txt, txt2, clearBtn, clearBtn2, plugin_advanced_arg] )
        # \u6574\u7406\u53cd\u590d\u51fa\u73b0\u7684\u63a7\u4ef6\u53e5\u67c4\u7ec4\u5408
        input_combo = [cookies, max_length_sl, md_dropdown, txt, txt2, top_p, temperature, chatbot, history, system_prompt, plugin_advanced_arg]
        output_combo = [cookies, chatbot, history, status]
        predict_args = dict(fn=ArgsGeneralWrapper(predict), inputs=input_combo, outputs=output_combo)
        # \u63d0\u4ea4\u6309\u94ae\u3001\u91cd\u7f6e\u6309\u94ae
        cancel_handles.append(txt.submit(**predict_args))
        cancel_handles.append(txt2.submit(**predict_args))
        cancel_handles.append(submitBtn.click(**predict_args))
        cancel_handles.append(submitBtn2.click(**predict_args))
        resetBtn.click(lambda: ([], [], "\u5df2\u91cd\u7f6e"), None, [chatbot, history, status])
        resetBtn2.click(lambda: ([], [], "\u5df2\u91cd\u7f6e"), None, [chatbot, history, status])
        clearBtn.click(lambda: ("",""), None, [txt, txt2])
        clearBtn2.click(lambda: ("",""), None, [txt, txt2])
        # \u57fa\u7840\u529f\u80fd\u533a\u7684\u56de\u8c03\u51fd\u6570\u6ce8\u518c
        for k in functional:
            if ("Visible" in functional[k]) and (not functional[k]["Visible"]): continue
            click_handle = functional[k]["Button"].click(fn=ArgsGeneralWrapper(predict), inputs=[*input_combo, gr.State(True), gr.State(k)], outputs=output_combo)
            cancel_handles.append(click_handle)
        # \u6587\u4ef6\u4e0a\u4f20\u533a\uff0c\u63a5\u6536\u6587\u4ef6\u540e\u4e0echatbot\u7684\u4e92\u52a8
        file_upload.upload(on_file_uploaded, [file_upload, chatbot, txt, txt2, checkboxes], [chatbot, txt, txt2])
        # \u51fd\u6570\u63d2\u4ef6-\u56fa\u5b9a\u6309\u94ae\u533a
        for k in crazy_fns:
            if not crazy_fns[k].get("AsButton", True): continue
            click_handle = crazy_fns[k]["Button"].click(ArgsGeneralWrapper(crazy_fns[k]["Function"]), [*input_combo, gr.State(PORT)], output_combo)
            click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
            cancel_handles.append(click_handle)
        # \u51fd\u6570\u63d2\u4ef6-\u4e0b\u62c9\u83dc\u5355\u4e0e\u968f\u53d8\u6309\u94ae\u7684\u4e92\u52a8
        def on_dropdown_changed(k):
            variant = crazy_fns[k]["Color"] if "Color" in crazy_fns[k] else "secondary"
            ret = {switchy_bt: gr.update(value=k, variant=variant)}
            if crazy_fns[k].get("AdvancedArgs", False): # \u662f\u5426\u5524\u8d77\u9ad8\u7ea7\u63d2\u4ef6\u53c2\u6570\u533a
                ret.update({plugin_advanced_arg: gr.update(visible=True,  label=f"\u63d2\u4ef6[{k}]\u7684\u9ad8\u7ea7\u53c2\u6570\u8bf4\u660e\uff1a" + crazy_fns[k].get("ArgsReminder", [f"\u6ca1\u6709\u63d0\u4f9b\u9ad8\u7ea7\u53c2\u6570\u529f\u80fd\u8bf4\u660e"]))})
            else:
                ret.update({plugin_advanced_arg: gr.update(visible=False, label=f"\u63d2\u4ef6[{k}]\u4e0d\u9700\u8981\u9ad8\u7ea7\u53c2\u6570\u3002")})
            return ret
        dropdown.select(on_dropdown_changed, [dropdown], [switchy_bt, plugin_advanced_arg] )
        def on_md_dropdown_changed(k):
            return {chatbot: gr.update(label="\u5f53\u524d\u6a21\u578b\uff1a"+k)}
        md_dropdown.select(on_md_dropdown_changed, [md_dropdown], [chatbot] )
        # \u968f\u53d8\u6309\u94ae\u7684\u56de\u8c03\u51fd\u6570\u6ce8\u518c
        def route(k, *args, **kwargs):
            if k in [r"\u6253\u5f00\u63d2\u4ef6\u5217\u8868", r"\u8bf7\u5148\u4ece\u63d2\u4ef6\u5217\u8868\u4e2d\u9009\u62e9"]: return
            yield from ArgsGeneralWrapper(crazy_fns[k]["Function"])(*args, **kwargs)
        click_handle = switchy_bt.click(route,[switchy_bt, *input_combo, gr.State(PORT)], output_combo)
        click_handle.then(on_report_generated, [file_upload, chatbot], [file_upload, chatbot])
        cancel_handles.append(click_handle)
        # \u7ec8\u6b62\u6309\u94ae\u7684\u56de\u8c03\u51fd\u6570\u6ce8\u518c
        stopBtn.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)
        stopBtn2.click(fn=None, inputs=None, outputs=None, cancels=cancel_handles)

    # gradio\u7684inbrowser\u89e6\u53d1\u4e0d\u592a\u7a33\u5b9a\uff0c\u56de\u6eda\u4ee3\u7801\u5230\u539f\u59cb\u7684\u6d4f\u89c8\u5668\u6253\u5f00\u51fd\u6570
    def auto_opentab_delay():
        import threading, webbrowser, time
        print(f"\u5982\u679c\u6d4f\u89c8\u5668\u6ca1\u6709\u81ea\u52a8\u6253\u5f00\uff0c\u8bf7\u590d\u5236\u5e76\u8f6c\u5230\u4ee5\u4e0bURL\uff1a")
        print(f"\t\uff08\u4eae\u8272\u4e3b\u9898\uff09: http://localhost:{PORT}")
        print(f"\t\uff08\u6697\u8272\u4e3b\u9898\uff09: http://localhost:{PORT}/?__theme=dark")
        def open():
            time.sleep(2)       # \u6253\u5f00\u6d4f\u89c8\u5668
            DARK_MODE, = get_conf('DARK_MODE')
            if DARK_MODE: webbrowser.open_new_tab(f"http://localhost:{PORT}/?__theme=dark")
            else: webbrowser.open_new_tab(f"http://localhost:{PORT}")
        threading.Thread(target=open, name="open-browser", daemon=True).start()
        threading.Thread(target=auto_update, name="self-upgrade", daemon=True).start()
        threading.Thread(target=warm_up_modules, name="warm-up", daemon=True).start()

    auto_opentab_delay()
    demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
        server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION,
        favicon_path="docs/logo.png", blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"])

--- a/main.py
+++ b/main.py
@@ -195,4 +195,6 @@
         threading.Thread(target=warm_up_modules, name="warm-up", daemon=True).start()

     auto_opentab_delay()
-    demo.queue(concurrency_count=CONCURRENT_COUNT).launch(server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION, favicon_path="docs/logo.png")
+    demo.queue(concurrency_count=CONCURRENT_COUNT).launch(
+        server_name="0.0.0.0", server_port=PORT, auth=AUTHENTICATION,
+        favicon_path="docs/logo.png", blocked_paths=["config.py","config_private.py","docker-compose.yml","Dockerfile"])


Improper Input Validation in GitHub repository pyload/pyload prior to 0.5.0b3.dev40.

Improper Input Validation

The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.

    def cast(self, typ, value):
        """
        cast value to given format.
        """
        if typ == "int":
            return int(value)

        elif typ == "float":
            return float(value)

        elif typ == "str":
            return "" if value is None else str(value)

        elif typ == "bytes":
            return b"" if value is None else bytes(value)

        elif typ == "bool":
            value = "" if value is None else str(value)
            return value.lower() in ("1", "true", "on", "yes", "y")

        elif typ == "time":
            value = "" if value is None else str(value)
            if not value:
                value = "0:00"
            if ":" not in value:
                value += ":00"
            return value

        elif typ in ("file", "folder"):
            return "" if value in (None, "") else os.path.realpath(os.path.expanduser(os.fsdecode(value)))

        else:
            return value

    def cast(self, typ, value):
        """
        cast value to given format.
        """
        if typ == "int":
            return int(value)

        elif typ == "float":
            return float(value)

        elif typ == "str":
            return "" if value is None else str(value)

        elif typ == "bytes":
            return b"" if value is None else bytes(value)

        elif typ == "bool":
            value = "" if value is None else str(value)
            return value.lower() in ("1", "true", "on", "yes", "y")

        elif typ == "time":
            default_value = "0:00"
            value = "" if value is None else str(value)
            if not value:
                value = default_value
            elif ":" not in value:
                value += ":00"

            hours, seconds = value.split(":", 1)
            if (
                hours.isnumeric()
                and seconds.isnumeric()
                and 0 <= int(hours) <= 23
                and 0 <= int(seconds) <= 59
            ):
                pass
            else:
                value = default_value

            return value

        elif typ in ("file", "folder"):
            return (
                ""
                if value in (None, "")
                else os.path.realpath(os.path.expanduser(os.fsdecode(value)))
            )

        else:
            return value

--- a/src/pyload/core/config/parser.py
+++ b/src/pyload/core/config/parser.py
@@ -19,15 +19,32 @@
             return value.lower() in ("1", "true", "on", "yes", "y")

         elif typ == "time":
+            default_value = "0:00"
             value = "" if value is None else str(value)
             if not value:
-                value = "0:00"
-            if ":" not in value:
+                value = default_value
+            elif ":" not in value:
                 value += ":00"
+
+            hours, seconds = value.split(":", 1)
+            if (
+                hours.isnumeric()
+                and seconds.isnumeric()
+                and 0 <= int(hours) <= 23
+                and 0 <= int(seconds) <= 59
+            ):
+                pass
+            else:
+                value = default_value
+
             return value

         elif typ in ("file", "folder"):
-            return "" if value in (None, "") else os.path.realpath(os.path.expanduser(os.fsdecode(value)))
+            return (
+                ""
+                if value in (None, "")
+                else os.path.realpath(os.path.expanduser(os.fsdecode(value)))
+            )

         else:
             return value


`@next-auth/upstash-redis-adapter` is the Upstash Redis adapter for NextAuth.js, which provides authentication for Next.js. Applications that use `next-auth` Email Provider and `@next-auth/upstash-redis-adapter` before v3.0.2 are affected by this vulnerability. The Upstash Redis adapter implementation did not check for both the identifier (email) and the token, but only checking for the identifier when verifying the token in the email callback flow. An attacker who knows about the victim's email could easily sign in as the victim, given the attacker also knows about the verification token's expired duration. The vulnerability is patched in v3.0.2. A workaround is available. Using Advanced Initialization, developers can check the requests and compare the query's token and identifier before proceeding.

Improper Authentication

When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.

    async createVerificationToken(verificationToken) {
      await setObjectAsJson(
        verificationTokenKeyPrefix + verificationToken.identifier,
        verificationToken
      )
      return verificationToken
    },

    async useVerificationToken(verificationToken) {
      const tokenKey = verificationTokenKeyPrefix + verificationToken.identifier

      const token = await client.get<VerificationToken>(tokenKey)
      if (!token) return null

      await client.del(tokenKey)
      return hydrateDates(token)
      // return reviveFromJson(token)
    },

    async createVerificationToken(verificationToken) {
      await setObjectAsJson(
        verificationTokenKeyPrefix +
          verificationToken.identifier +
          ":" +
          verificationToken.token,
        verificationToken
      )
      return verificationToken
    },

    async useVerificationToken(verificationToken) {
      const tokenKey =
        verificationTokenKeyPrefix +
        verificationToken.identifier +
        ":" +
        verificationToken.token

      const token = await client.get<VerificationToken>(tokenKey)
      if (!token) return null

      await client.del(tokenKey)
      return hydrateDates(token)
      // return reviveFromJson(token)
    },

--- a/packages/adapter-upstash-redis/src/index.ts
+++ b/packages/adapter-upstash-redis/src/index.ts
@@ -1,6 +1,9 @@
     async createVerificationToken(verificationToken) {
       await setObjectAsJson(
-        verificationTokenKeyPrefix + verificationToken.identifier,
+        verificationTokenKeyPrefix +
+          verificationToken.identifier +
+          ":" +
+          verificationToken.token,
         verificationToken
       )
       return verificationToken

--- a/packages/adapter-upstash-redis/src/index.ts
+++ b/packages/adapter-upstash-redis/src/index.ts
@@ -1,5 +1,9 @@
     async useVerificationToken(verificationToken) {
-      const tokenKey = verificationTokenKeyPrefix + verificationToken.identifier
+      const tokenKey =
+        verificationTokenKeyPrefix +
+        verificationToken.identifier +
+        ":" +
+        verificationToken.token

       const token = await client.get<VerificationToken>(tokenKey)
       if (!token) return null


A flaw was found in the Keylime registrar that could allow a bypass of the challenge-response protocol during agent registration. This issue may allow an attacker to impersonate an agent and hide the true status of a monitored machine if the fake agent is added to the verifier list by a legitimate user, resulting in a breach of the integrity of the registrar database.

Missing Authorization

The product does not perform an authorization check when an actor attempts to access a resource or perform an action.

Authorization Bypass Through User-Controlled Key

The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.

    def do_PUT(self) -> None:
        """This method handles the PUT requests to add agents to the Registrar Server.

        Currently, only agents resources are available for PUTing, i.e. /agents. All other PUT uri's
        will return errors.
        """
        session = SessionManager().make_session(engine)

        _, agent_id = self._validate_input("PUT", True)
        if not agent_id:
            return

        try:
            content_length = int(self.headers.get("Content-Length", 0))
            if content_length == 0:
                web_util.echo_json_response(self, 400, "Expected non zero content length")
                logger.warning("PUT for %s returning 400 response. Expected non zero content length.", agent_id)
                return

            post_body = self.rfile.read(content_length)
            json_body = json.loads(post_body)

            auth_tag = json_body["auth_tag"]
            try:
                agent = session.query(RegistrarMain).filter_by(agent_id=agent_id).first()
            except NoResultFound as e:
                raise Exception("attempting to activate agent before requesting " f"registrar for {agent_id}") from e
            except SQLAlchemyError as e:
                logger.error("SQLAlchemy Error: %s", e)
                raise

            assert agent
            assert isinstance(agent.key, str)
            ex_mac = crypto.do_hmac(agent.key.encode(), agent_id)
            if ex_mac == auth_tag:
                try:
                    session.query(RegistrarMain).filter(RegistrarMain.agent_id == agent_id).update(
                        {"active": int(True)}
                    )
                    session.commit()
                except SQLAlchemyError as e:
                    logger.error("SQLAlchemy Error: %s", e)
                    raise
            else:
                raise Exception(f"Auth tag {auth_tag} does not match expected value {ex_mac}")

            web_util.echo_json_response(self, 200, "Success")
            logger.info("PUT activated: %s", agent_id)
        except Exception as e:
            web_util.echo_json_response(self, 400, f"Error: {str(e)}")
            logger.warning("PUT for %s returning 400 response. Error: %s", agent_id, e)
            logger.exception(e)
            return

    def do_PUT(self) -> None:
        """This method handles the PUT requests to add agents to the Registrar Server.

        Currently, only agents resources are available for PUTing, i.e. /agents. All other PUT uri's
        will return errors.
        """
        session = SessionManager().make_session(engine)

        _, agent_id = self._validate_input("PUT", True)
        if not agent_id:
            return

        try:
            content_length = int(self.headers.get("Content-Length", 0))
            if content_length == 0:
                web_util.echo_json_response(self, 400, "Expected non zero content length")
                logger.warning("PUT for %s returning 400 response. Expected non zero content length.", agent_id)
                return

            post_body = self.rfile.read(content_length)
            json_body = json.loads(post_body)

            auth_tag = json_body["auth_tag"]
            try:
                agent = session.query(RegistrarMain).filter_by(agent_id=agent_id).first()
            except NoResultFound as e:
                raise Exception("attempting to activate agent before requesting " f"registrar for {agent_id}") from e
            except SQLAlchemyError as e:
                logger.error("SQLAlchemy Error: %s", e)
                raise

            assert agent
            assert isinstance(agent.key, str)
            ex_mac = crypto.do_hmac(agent.key.encode(), agent_id)
            if ex_mac == auth_tag:
                try:
                    session.query(RegistrarMain).filter(RegistrarMain.agent_id == agent_id).update(
                        {"active": int(True)}
                    )
                    session.commit()
                except SQLAlchemyError as e:
                    logger.error("SQLAlchemy Error: %s", e)
                    raise
            else:
                if agent_id and session.query(RegistrarMain).filter_by(agent_id=agent_id).delete():
                    try:
                        session.commit()
                    except SQLAlchemyError as e:
                        logger.error("SQLAlchemy Error: %s", e)
                        raise

                raise Exception(
                    f"Auth tag {auth_tag} for agent {agent_id} does not match expected value. The agent has been deleted from database, and a restart of it will be required"
                )

            web_util.echo_json_response(self, 200, "Success")
            logger.info("PUT activated: %s", agent_id)
        except Exception as e:
            web_util.echo_json_response(self, 400, f"Error: {str(e)}")
            logger.warning("PUT for %s returning 400 response. Error: %s", agent_id, e)
            logger.exception(e)
            return

--- a/keylime/registrar_common.py
+++ b/keylime/registrar_common.py
@@ -42,7 +42,16 @@
                     logger.error("SQLAlchemy Error: %s", e)
                     raise
             else:
-                raise Exception(f"Auth tag {auth_tag} does not match expected value {ex_mac}")
+                if agent_id and session.query(RegistrarMain).filter_by(agent_id=agent_id).delete():
+                    try:
+                        session.commit()
+                    except SQLAlchemyError as e:
+                        logger.error("SQLAlchemy Error: %s", e)
+                        raise
+
+                raise Exception(
+                    f"Auth tag {auth_tag} for agent {agent_id} does not match expected value. The agent has been deleted from database, and a restart of it will be required"
+                )

             web_util.echo_json_response(self, 200, "Success")
             logger.info("PUT activated: %s", agent_id)


main.py in Searchor before 2.4.2 uses eval on CLI input, which may cause unexpected code execution.

Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')

The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.

def search(engine, query, open, copy):
    try:
        url = eval(
            f"Engine.{engine}.search('{query}', copy_url={copy}, open_web={open})"
        )
        click.echo(url)
        searchor.history.update(engine, query, url)
        if open:
            click.echo("opening browser...")
        if copy:
            click.echo("link copied to clipboard")
    except AttributeError:
        print("engine not recognized")

def search(engine, query, open, copy):
    try:
        url = Engine[engine].search(query, copy_url=copy, open_web=open)
        click.echo(url)
        searchor.history.update(engine, query, url)
        if open:
            click.echo("opening browser...")
        if copy:
            click.echo("link copied to clipboard")
    except AttributeError:
        print("engine not recognized")

--- a/src/searchor/main.py
+++ b/src/searchor/main.py
@@ -1,8 +1,6 @@
 def search(engine, query, open, copy):
     try:
-        url = eval(
-            f"Engine.{engine}.search('{query}', copy_url={copy}, open_web={open})"
-        )
+        url = Engine[engine].search(query, copy_url=copy, open_web=open)
         click.echo(url)
         searchor.history.update(engine, query, url)
         if open:


A vulnerability in gaizhenbiao/chuanhuchatgpt version 20240802 allows attackers to access, copy, and delete other users' chat histories. This issue arises due to improper handling of session data and lack of access control mechanisms, enabling attackers to view and manipulate chat histories of other users.

Improper Access Control

The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.

    def delete_chat_history(self, filename):
        if filename == "CANCELED":
            return gr.update(), gr.update(), gr.update()
        if filename == "":
            return i18n("\u4f60\u6ca1\u6709\u9009\u62e9\u4efb\u4f55\u5bf9\u8bdd\u5386\u53f2"), gr.update(), gr.update()
        if not filename.endswith(".json"):
            filename += ".json"
        if filename == os.path.basename(filename):
            history_file_path = os.path.join(HISTORY_DIR, self.user_name, filename)
        else:
            history_file_path = filename
        md_history_file_path = history_file_path[:-5] + ".md"
        try:
            os.remove(history_file_path)
            os.remove(md_history_file_path)
            return i18n("\u5220\u9664\u5bf9\u8bdd\u5386\u53f2\u6210\u529f"), get_history_list(self.user_name), []
        except:
            logging.info(f"\u5220\u9664\u5bf9\u8bdd\u5386\u53f2\u5931\u8d25 {history_file_path}")
            return (
                i18n("\u5bf9\u8bdd\u5386\u53f2") + filename + i18n("\u5df2\u7ecf\u88ab\u5220\u9664\u5566"),
                get_history_list(self.user_name),
                [],
            )

def save_file(filename, model, chatbot):
    system = model.system_prompt
    history = model.history
    user_name = model.user_name
    os.makedirs(os.path.join(HISTORY_DIR, user_name), exist_ok=True)
    if filename is None:
        filename = new_auto_history_filename(user_name)
    if filename.endswith(".md"):
        filename = filename[:-3]
    if not filename.endswith(".json") and not filename.endswith(".md"):
        filename += ".json"
    if filename == ".json":
        raise Exception("\u6587\u4ef6\u540d\u4e0d\u80fd\u4e3a\u7a7a")

    json_s = {
        "system": system,
        "history": history,
        "chatbot": chatbot,
        "model_name": model.model_name,
        "single_turn": model.single_turn,
        "temperature": model.temperature,
        "top_p": model.top_p,
        "n_choices": model.n_choices,
        "stop_sequence": model.stop_sequence,
        "token_upper_limit": model.token_upper_limit,
        "max_generation_token": model.max_generation_token,
        "presence_penalty": model.presence_penalty,
        "frequency_penalty": model.frequency_penalty,
        "logit_bias": model.logit_bias,
        "user_identifier": model.user_identifier,
        "stream": model.stream,
        "metadata": model.metadata,
    }
    if not filename == os.path.basename(filename):
        history_file_path = filename
    else:
        history_file_path = os.path.join(HISTORY_DIR, user_name, filename)

    with open(history_file_path, "w", encoding="utf-8") as f:
        json.dump(json_s, f, ensure_ascii=False, indent=4)

    filename = os.path.basename(filename)
    filename_md = filename[:-5] + ".md"
    md_s = f"system: \n- {system} \n"
    for data in history:
        md_s += f"\n{data['role']}: \n- {data['content']} \n"
    with open(
        os.path.join(HISTORY_DIR, user_name, filename_md), "w", encoding="utf8"
    ) as f:
        f.write(md_s)
    return os.path.join(HISTORY_DIR, user_name, filename)

    def delete_chat_history(self, filename):
        if filename == "CANCELED":
            return gr.update(), gr.update(), gr.update()
        if filename == "":
            return i18n("\u4f60\u6ca1\u6709\u9009\u62e9\u4efb\u4f55\u5bf9\u8bdd\u5386\u53f2"), gr.update(), gr.update()
        if not filename.endswith(".json"):
            filename += ".json"
        if filename == os.path.basename(filename):
            history_file_path = os.path.join(HISTORY_DIR, self.user_name, filename)
        else:
            history_file_path = filename
        md_history_file_path = history_file_path[:-5] + ".md"
        # check if history file path matches user_name
        # if user access control is not enabled, user_name is empty, don't check
        assert os.path.dirname(history_file_path) == self.user_name or self.user_name == ""
        assert os.path.dirname(md_history_file_path) == self.user_name or self.user_name == ""
        try:
            os.remove(history_file_path)
            os.remove(md_history_file_path)
            return i18n("\u5220\u9664\u5bf9\u8bdd\u5386\u53f2\u6210\u529f"), get_history_list(self.user_name), []
        except:
            logging.info(f"\u5220\u9664\u5bf9\u8bdd\u5386\u53f2\u5931\u8d25 {history_file_path}")
            return (
                i18n("\u5bf9\u8bdd\u5386\u53f2") + filename + i18n("\u5df2\u7ecf\u88ab\u5220\u9664\u5566"),
                get_history_list(self.user_name),
                [],
            )

def save_file(filename, model, chatbot):
    system = model.system_prompt
    history = model.history
    user_name = model.user_name
    os.makedirs(os.path.join(HISTORY_DIR, user_name), exist_ok=True)
    if filename is None:
        filename = new_auto_history_filename(user_name)
    if filename.endswith(".md"):
        filename = filename[:-3]
    if not filename.endswith(".json") and not filename.endswith(".md"):
        filename += ".json"
    if filename == ".json":
        raise Exception("\u6587\u4ef6\u540d\u4e0d\u80fd\u4e3a\u7a7a")

    json_s = {
        "system": system,
        "history": history,
        "chatbot": chatbot,
        "model_name": model.model_name,
        "single_turn": model.single_turn,
        "temperature": model.temperature,
        "top_p": model.top_p,
        "n_choices": model.n_choices,
        "stop_sequence": model.stop_sequence,
        "token_upper_limit": model.token_upper_limit,
        "max_generation_token": model.max_generation_token,
        "presence_penalty": model.presence_penalty,
        "frequency_penalty": model.frequency_penalty,
        "logit_bias": model.logit_bias,
        "user_identifier": model.user_identifier,
        "stream": model.stream,
        "metadata": model.metadata,
    }
    if not filename == os.path.basename(filename):
        history_file_path = filename
    else:
        history_file_path = os.path.join(HISTORY_DIR, user_name, filename)

    # check if history file path matches user_name
    # if user access control is not enabled, user_name is empty, don't check
    assert os.path.dirname(history_file_path) == model.user_name or model.user_name == ""
    with open(history_file_path, "w", encoding="utf-8") as f:
        json.dump(json_s, f, ensure_ascii=False, indent=4)

    filename = os.path.basename(filename)
    filename_md = filename[:-5] + ".md"
    md_s = f"system: \n- {system} \n"
    for data in history:
        md_s += f"\n{data['role']}: \n- {data['content']} \n"
    with open(
        os.path.join(HISTORY_DIR, user_name, filename_md), "w", encoding="utf8"
    ) as f:
        f.write(md_s)
    return os.path.join(HISTORY_DIR, user_name, filename)

--- a/modules/models/base_model.py
+++ b/modules/models/base_model.py
@@ -10,6 +10,10 @@
         else:
             history_file_path = filename
         md_history_file_path = history_file_path[:-5] + ".md"
+        # check if history file path matches user_name
+        # if user access control is not enabled, user_name is empty, don't check
+        assert os.path.dirname(history_file_path) == self.user_name or self.user_name == ""
+        assert os.path.dirname(md_history_file_path) == self.user_name or self.user_name == ""
         try:
             os.remove(history_file_path)
             os.remove(md_history_file_path)

--- a/modules/utils.py
+++ b/modules/utils.py
@@ -36,6 +36,9 @@
     else:
         history_file_path = os.path.join(HISTORY_DIR, user_name, filename)

+    # check if history file path matches user_name
+    # if user access control is not enabled, user_name is empty, don't check
+    assert os.path.dirname(history_file_path) == model.user_name or model.user_name == ""
     with open(history_file_path, "w", encoding="utf-8") as f:
         json.dump(json_s, f, ensure_ascii=False, indent=4)


Uptime Kuma is an easy-to-use self-hosted monitoring tool. Prior to version 1.23.9, the application uses WebSocket (with Socket.io), but it does not verify that the source of communication is valid. This allows third-party website to access the application on behalf of their client. When connecting to the server using Socket.IO, the server does not validate the `Origin` header leading to other site being able to open connections to the server and communicate with it. Other websites still need to authenticate to access most features, however this can be used to circumvent firewall protections made in place by people deploying the application.

Without origin validation, Javascript executed from another origin would be allowed to connect to the application without any user interaction. Without login credentials, such a connection is unable to access protected endpoints containing sensitive data of the application. However, such a connection may allow attacker to further exploit unseen vulnerabilities of the application. Users with "No-auth" mode configured who are relying on a reverse proxy or firewall to provide protection to the application would be especially vulnerable as it would grant the attacker full access to the application.

In version 1.23.9, additional verification of the HTTP Origin header has been added to the socket.io connection handler. By default, if the `Origin` header is present, it would be checked against the Host header. Connection would be denied if the hostnames do not match, which would indicate that the request is cross-origin. Connection would be allowed if the `Origin` header is not present. Users can override this behavior by setting environment variable `UPTIME_KUMA_WS_ORIGIN_CHECK=bypass`.

Origin Validation Error

The product does not properly verify that the source of data or communication is valid.

        this.io = new Server(this.httpServer, {
            allowRequest: (req, callback) => {
                let isOriginValid = true;
                const bypass = isDev || process.env.UPTIME_KUMA_WS_ORIGIN_CHECK === "bypass";

                if (!bypass) {
                    let host = req.headers.host;

                    // If this is set, it means the request is from the browser
                    let origin = req.headers.origin;

                    // If this is from the browser, check if the origin is allowed
                    if (origin) {
                        try {
                            let originURL = new URL(origin);

                            if (host !== originURL.host) {
                                isOriginValid = false;
                                log.error("auth", `Origin (${origin}) does not match host (${host}), IP: ${req.socket.remoteAddress}`);
                            }
                        } catch (e) {
                            // Invalid origin url, probably not from browser
                            isOriginValid = false;
                            log.error("auth", `Invalid origin url (${origin}), IP: ${req.socket.remoteAddress}`);
                        }
                    } else {
                        log.info("auth", `Origin is not set, IP: ${req.socket.remoteAddress}`);
                    }
                } else {
                    log.debug("auth", "Origin check is bypassed");
                }

                callback(null, isOriginValid);
            }
        });

if (!process.env.UPTIME_KUMA_WS_ORIGIN_CHECK) {
    process.env.UPTIME_KUMA_WS_ORIGIN_CHECK = "cors-like";
}

log.info("server", "Node Env: " + process.env.NODE_ENV);
log.info("server", "Inside Container: " + (process.env.UPTIME_KUMA_IS_CONTAINER === "1"));
log.info("server", "WebSocket Origin Check: " + process.env.UPTIME_KUMA_WS_ORIGIN_CHECK);

--- a/server/uptime-kuma-server.js
+++ b/server/uptime-kuma-server.js
@@ -1 +1,35 @@
-        this.io = new Server(this.httpServer);
+        this.io = new Server(this.httpServer, {
+            allowRequest: (req, callback) => {
+                let isOriginValid = true;
+                const bypass = isDev || process.env.UPTIME_KUMA_WS_ORIGIN_CHECK === "bypass";
+
+                if (!bypass) {
+                    let host = req.headers.host;
+
+                    // If this is set, it means the request is from the browser
+                    let origin = req.headers.origin;
+
+                    // If this is from the browser, check if the origin is allowed
+                    if (origin) {
+                        try {
+                            let originURL = new URL(origin);
+
+                            if (host !== originURL.host) {
+                                isOriginValid = false;
+                                log.error("auth", `Origin (${origin}) does not match host (${host}), IP: ${req.socket.remoteAddress}`);
+                            }
+                        } catch (e) {
+                            // Invalid origin url, probably not from browser
+                            isOriginValid = false;
+                            log.error("auth", `Invalid origin url (${origin}), IP: ${req.socket.remoteAddress}`);
+                        }
+                    } else {
+                        log.info("auth", `Origin is not set, IP: ${req.socket.remoteAddress}`);
+                    }
+                } else {
+                    log.debug("auth", "Origin check is bypassed");
+                }
+
+                callback(null, isOriginValid);
+            }
+        });

--- /dev/null
+++ b/server/uptime-kuma-server.js
@@ -0,0 +1,7 @@
+if (!process.env.UPTIME_KUMA_WS_ORIGIN_CHECK) {
+    process.env.UPTIME_KUMA_WS_ORIGIN_CHECK = "cors-like";
+}
+
+log.info("server", "Node Env: " + process.env.NODE_ENV);
+log.info("server", "Inside Container: " + (process.env.UPTIME_KUMA_IS_CONTAINER === "1"));
+log.info("server", "WebSocket Origin Check: " + process.env.UPTIME_KUMA_WS_ORIGIN_CHECK);


Authelia is a a single sign-on multi-factor portal for web apps. This affects uses who are using nginx ngx_http_auth_request_module with Authelia, it allows a malicious individual who crafts a malformed HTTP request to bypass the authentication mechanism. It additionally could theoretically affect other proxy servers, but all of the ones we officially support except nginx do not allow malformed URI paths. The problem is rectified entirely in v4.29.3. As this patch is relatively straightforward we can back port this to any version upon request. Alternatively we are supplying a git patch to 4.25.1 which should be relatively straightforward to apply to any version, the git patches for specific versions can be found in the references. The most relevant workaround is upgrading. You can also add a block which fails requests that contains a malformed URI in the internal location block.

func VerifyGet(cfg schema.AuthenticationBackendConfiguration) middlewares.RequestHandler {
	refreshProfile, refreshProfileInterval := getProfileRefreshSettings(cfg)

	return func(ctx *middlewares.AutheliaCtx) {
		ctx.Logger.Tracef("Headers=%s", ctx.Request.Header.String())
		targetURL, err := ctx.GetOriginalURL()

		if err != nil {
			ctx.Error(fmt.Errorf("Unable to parse target URL: %s", err), operationFailedMessage)
			return
		}

		if !isSchemeHTTPS(targetURL) && !isSchemeWSS(targetURL) {
			ctx.Logger.Error(fmt.Errorf("Scheme of target URL %s must be secure since cookies are "+
				"only transported over a secure connection for security reasons", targetURL.String()))
			ctx.ReplyUnauthorized()

			return
		}

		if !isURLUnderProtectedDomain(targetURL, ctx.Configuration.Session.Domain) {
			ctx.Logger.Error(fmt.Errorf("The target URL %s is not under the protected domain %s",
				targetURL.String(), ctx.Configuration.Session.Domain))
			ctx.ReplyUnauthorized()

			return
		}

		isBasicAuth, username, name, groups, emails, authLevel, err := verifyAuth(ctx, targetURL, refreshProfile, refreshProfileInterval)

		method := ctx.XForwardedMethod()

		if err != nil {
			ctx.Logger.Error(fmt.Sprintf("Error caught when verifying user authorization: %s", err))

			if err := updateActivityTimestamp(ctx, isBasicAuth, username); err != nil {
				ctx.Error(fmt.Errorf("Unable to update last activity: %s", err), operationFailedMessage)
				return
			}

			handleUnauthorized(ctx, targetURL, isBasicAuth, username, method)

			return
		}

		authorized := isTargetURLAuthorized(ctx.Providers.Authorizer, *targetURL, username,
			groups, ctx.RemoteIP(), method, authLevel)

		switch authorized {
		case Forbidden:
			ctx.Logger.Infof("Access to %s is forbidden to user %s", targetURL.String(), username)
			ctx.ReplyForbidden()
		case NotAuthorized:
			handleUnauthorized(ctx, targetURL, isBasicAuth, username, method)
		case Authorized:
			setForwardedHeaders(&ctx.Response.Header, username, name, groups, emails)
		}

		if err := updateActivityTimestamp(ctx, isBasicAuth, username); err != nil {
			ctx.Error(fmt.Errorf("Unable to update last activity: %s", err), operationFailedMessage)
		}
	}
}

func VerifyGet(cfg schema.AuthenticationBackendConfiguration) middlewares.RequestHandler {
	refreshProfile, refreshProfileInterval := getProfileRefreshSettings(cfg)

	return func(ctx *middlewares.AutheliaCtx) {
		ctx.Logger.Tracef("Headers=%s", ctx.Request.Header.String())
		targetURL, err := ctx.GetOriginalURL()

		if err != nil {
			ctx.Logger.Error(fmt.Errorf("Unable to parse target URL: %s", err))
			ctx.ReplyUnauthorized()

			return
		}

		if !isSchemeHTTPS(targetURL) && !isSchemeWSS(targetURL) {
			ctx.Logger.Error(fmt.Errorf("Scheme of target URL %s must be secure since cookies are "+
				"only transported over a secure connection for security reasons", targetURL.String()))
			ctx.ReplyUnauthorized()

			return
		}

		if !isURLUnderProtectedDomain(targetURL, ctx.Configuration.Session.Domain) {
			ctx.Logger.Error(fmt.Errorf("The target URL %s is not under the protected domain %s",
				targetURL.String(), ctx.Configuration.Session.Domain))
			ctx.ReplyUnauthorized()

			return
		}

		isBasicAuth, username, name, groups, emails, authLevel, err := verifyAuth(ctx, targetURL, refreshProfile, refreshProfileInterval)

		method := ctx.XForwardedMethod()

		if err != nil {
			ctx.Logger.Error(fmt.Sprintf("Error caught when verifying user authorization: %s", err))

			if err := updateActivityTimestamp(ctx, isBasicAuth, username); err != nil {
				ctx.Error(fmt.Errorf("Unable to update last activity: %s", err), operationFailedMessage)
				return
			}

			handleUnauthorized(ctx, targetURL, isBasicAuth, username, method)

			return
		}

		authorized := isTargetURLAuthorized(ctx.Providers.Authorizer, *targetURL, username,
			groups, ctx.RemoteIP(), method, authLevel)

		switch authorized {
		case Forbidden:
			ctx.Logger.Infof("Access to %s is forbidden to user %s", targetURL.String(), username)
			ctx.ReplyForbidden()
		case NotAuthorized:
			handleUnauthorized(ctx, targetURL, isBasicAuth, username, method)
		case Authorized:
			setForwardedHeaders(&ctx.Response.Header, username, name, groups, emails)
		}

		if err := updateActivityTimestamp(ctx, isBasicAuth, username); err != nil {
			ctx.Error(fmt.Errorf("Unable to update last activity: %s", err), operationFailedMessage)
		}
	}
}

--- a/internal/handlers/handler_verify.go
+++ b/internal/handlers/handler_verify.go
@@ -6,7 +6,9 @@
 		targetURL, err := ctx.GetOriginalURL()

 		if err != nil {
-			ctx.Error(fmt.Errorf("Unable to parse target URL: %s", err), operationFailedMessage)
+			ctx.Logger.Error(fmt.Errorf("Unable to parse target URL: %s", err))
+			ctx.ReplyUnauthorized()
+
 			return
 		}


bodymen before 1.1.1 is vulnerable to Prototype Pollution. The handler function could be tricked into adding or modifying properties of Object.prototype using a __proto__ payload.

export function handler (type, name, fn) {
  if (arguments.length > 2) {
    handlers[type][name] = fn
  }

  return handlers[type][name]
}

export function handler (type, name, fn) {
  if (
    type === 'constructor' ||
    type === '__proto__' ||
    name === 'constructor' ||
    name === '__proto__'
  ) {
    return
  }
  if (arguments.length > 2) {
    handlers[type][name] = fn
  }

  return handlers[type][name]
}

--- a/src/index.js
+++ b/src/index.js
@@ -1,4 +1,12 @@
 export function handler (type, name, fn) {
+  if (
+    type === 'constructor' ||
+    type === '__proto__' ||
+    name === 'constructor' ||
+    name === '__proto__'
+  ) {
+    return
+  }
   if (arguments.length > 2) {
     handlers[type][name] = fn
   }

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2019-10792:latest
# bash /workspace/fix-run.sh
set -e

cd /workspace/bodymen
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
npx babel-node test/index.js

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2019-10792:latest
# bash /workspace/unit_test.sh
set -e

cd /workspace/bodymen
git apply --whitespace=nowarn /workspace/fix.patch
npx babel-node test/index.js


An OS command injection vulnerability exists in web2py 2.24.1 and earlier. When the product is configured to use notifySendHandler for logging (not the default configuration), a crafted web request may execute an arbitrary OS command on the web server using the product.

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.

    def emit(self, record):
        if tkinter:
            msg = self.format(record)
            os.system("notify-send '%s'" % msg)

    def emit(self, record):
        if tkinter:
            msg = self.format(record)
            subprocess.run(["notify-send", msg], check=False, timeout=2)

--- a/gluon/messageboxhandler.py
+++ b/gluon/messageboxhandler.py
@@ -1,4 +1,4 @@
     def emit(self, record):
         if tkinter:
             msg = self.format(record)
-            os.system("notify-send '%s'" % msg)
+            subprocess.run(["notify-send", msg], check=False, timeout=2)


Allocation of Resources Without Limits or Throttling in GitHub repository ikus060/rdiffweb prior to 2.4.8.

The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor.

class SshForm(CherryForm):
    title = StringField(
        _('Title'),
        description=_('The title is an optional description to identify the key. e.g.: bob@thinkpad-t530'),
        validators=[validators.data_required()],
    )
    key = StringField(
        _('Key'),
        widget=TextArea(),
        description=_(
            "Enter a SSH public key. It should start with 'ssh-dss', 'ssh-ed25519', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384' or 'ecdsa-sha2-nistp521'."
        ),
        validators=[validators.data_required(), validate_key],
    )
    fingerprint = StringField('Fingerprint')

class SshForm(CherryForm):
    title = StringField(
        _('Title'),
        description=_('The title is an optional description to identify the key. e.g.: bob@thinkpad-t530'),
        validators=[
            validators.data_required(),
            validators.length(
                max=256,
                message=_('Title too long.'),
            ),
        ],
    )
    key = StringField(
        _('Key'),
        widget=TextArea(),
        description=_(
            "Enter a SSH public key. It should start with 'ssh-dss', 'ssh-ed25519', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384' or 'ecdsa-sha2-nistp521'."
        ),
        validators=[validators.data_required(), validate_key],
    )
    fingerprint = StringField('Fingerprint')

--- a/rdiffweb/controller/pref_sshkeys.py
+++ b/rdiffweb/controller/pref_sshkeys.py
@@ -2,7 +2,13 @@
     title = StringField(
         _('Title'),
         description=_('The title is an optional description to identify the key. e.g.: bob@thinkpad-t530'),
-        validators=[validators.data_required()],
+        validators=[
+            validators.data_required(),
+            validators.length(
+                max=256,
+                message=_('Title too long.'),
+            ),
+        ],
     )
     key = StringField(
         _('Key'),

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2022-3298:latest
# bash /workspace/fix-run.sh
set -e

cd /workspace/rdiffweb
git apply --whitespace=nowarn /workspace/test.patch /workspace/fix.patch
/workspace/PoC_env/CVE-2022-3298/bin/python -m pytest rdiffweb/controller/tests/test_page_prefs_ssh.py -v -k "test_add_with_title_too_long"

#!/bin/bash
# From ghcr.io/anonymous2578-data/cve-2022-3298:latest
# bash /workspace/unit_test.sh
set -e

cd /workspace/rdiffweb
git apply --whitespace=nowarn /workspace/fix.patch
/workspace/PoC_env/CVE-2022-3298/bin/python -m pytest rdiffweb/controller/tests/test_page_prefs_ssh.py -v


An issue was discovered in OpenStack Horizon before 15.3.2, 16.x before 16.2.1, 17.x and 18.x before 18.3.3, 18.4.x, and 18.5.x. There is a lack of validation of the "next" parameter, which would allow someone to supply a malicious URL in Horizon that can cause an automatic redirect to the provided malicious URL.

URL Redirection to Untrusted Site ('Open Redirect')

The web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a redirect.

    def get_context_data(self, **kwargs):
        """Returns the template context, including the workflow class.

        This method should be overridden in subclasses to provide additional
        context data to the template.
        """
        context = super(WorkflowView, self).get_context_data(**kwargs)
        workflow = self.get_workflow()
        workflow.verify_integrity()
        context[self.context_object_name] = workflow
        next = self.request.GET.get(workflow.redirect_param_name)
        context['REDIRECT_URL'] = next
        context['layout'] = self.get_layout()
        # For consistency with Workflow class
        context['modal'] = 'modal' in context['layout']

        if ADD_TO_FIELD_HEADER in self.request.META:
            context['add_to_field'] = self.request.META[ADD_TO_FIELD_HEADER]
        return context

    def get_context_data(self, **kwargs):
        """Returns the template context, including the workflow class.

        This method should be overridden in subclasses to provide additional
        context data to the template.
        """
        context = super(WorkflowView, self).get_context_data(**kwargs)
        workflow = self.get_workflow()
        workflow.verify_integrity()
        context[self.context_object_name] = workflow

        redirect_to = self.request.GET.get(workflow.redirect_param_name)
        # Make sure the requested redirect is safe
        if redirect_to and not utils_http.is_safe_url(
                url=redirect_to,
                allowed_hosts=[self.request.get_host()]):
            redirect_to = None
        context['REDIRECT_URL'] = redirect_to

        context['layout'] = self.get_layout()
        # For consistency with Workflow class
        context['modal'] = 'modal' in context['layout']

        if ADD_TO_FIELD_HEADER in self.request.META:
            context['add_to_field'] = self.request.META[ADD_TO_FIELD_HEADER]
        return context

--- a/horizon/workflows/views.py
+++ b/horizon/workflows/views.py
@@ -8,8 +8,15 @@
         workflow = self.get_workflow()
         workflow.verify_integrity()
         context[self.context_object_name] = workflow
-        next = self.request.GET.get(workflow.redirect_param_name)
-        context['REDIRECT_URL'] = next
+
+        redirect_to = self.request.GET.get(workflow.redirect_param_name)
+        # Make sure the requested redirect is safe
+        if redirect_to and not utils_http.is_safe_url(
+                url=redirect_to,
+                allowed_hosts=[self.request.get_host()]):
+            redirect_to = None
+        context['REDIRECT_URL'] = redirect_to
+
         context['layout'] = self.get_layout()
         # For consistency with Workflow class
         context['modal'] = 'modal' in context['layout']


The thefuck (aka The Fuck) package before 3.31 for Python allows Path Traversal that leads to arbitrary file deletion via the "undo archive operation" feature.

External Control of File Name or Path

The product allows user input to control or influence paths or file names that are used in filesystem operations.

Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

def side_effect(old_cmd, command):
    with tarfile.TarFile(_tar_file(old_cmd.script_parts)[0]) as archive:
        for file in archive.getnames():
            try:
                os.remove(file)
            except OSError:
                # does not try to remove directories as we cannot know if they
                # already existed before
                pass

def side_effect(old_cmd, command):
    with zipfile.ZipFile(_zip_file(old_cmd), 'r') as archive:
        for file in archive.namelist():
            try:
                os.remove(file)
            except OSError:
                # does not try to remove directories as we cannot know if they
                # already existed before
                pass

def side_effect(old_cmd, command):
    with tarfile.TarFile(_tar_file(old_cmd.script_parts)[0]) as archive:
        for file in archive.getnames():
            if not os.path.abspath(file).startswith(os.getcwd()):
                # it's unsafe to overwrite files outside of the current directory
                continue

            try:
                os.remove(file)
            except OSError:
                # does not try to remove directories as we cannot know if they
                # already existed before
                pass

def side_effect(old_cmd, command):
    with zipfile.ZipFile(_zip_file(old_cmd), 'r') as archive:
        for file in archive.namelist():
            if not os.path.abspath(file).startswith(os.getcwd()):
                # it's unsafe to overwrite files outside of the current directory
                continue

            try:
                os.remove(file)
            except OSError:
                # does not try to remove directories as we cannot know if they
                # already existed before
                pass

--- a/thefuck/rules/dirty_untar.py
+++ b/thefuck/rules/dirty_untar.py
@@ -1,6 +1,10 @@
 def side_effect(old_cmd, command):
     with tarfile.TarFile(_tar_file(old_cmd.script_parts)[0]) as archive:
         for file in archive.getnames():
+            if not os.path.abspath(file).startswith(os.getcwd()):
+                # it's unsafe to overwrite files outside of the current directory
+                continue
+
             try:
                 os.remove(file)
             except OSError:

--- a/thefuck/rules/dirty_unzip.py
+++ b/thefuck/rules/dirty_unzip.py
@@ -1,6 +1,10 @@
 def side_effect(old_cmd, command):
     with zipfile.ZipFile(_zip_file(old_cmd), 'r') as archive:
         for file in archive.namelist():
+            if not os.path.abspath(file).startswith(os.getcwd()):
+                # it's unsafe to overwrite files outside of the current directory
+                continue
+
             try:
                 os.remove(file)
             except OSError:


node-rules including 3.0.0 and prior to 5.0.0 allows injection of arbitrary commands. The argument rules of function "fromJSON()" can be controlled by users without any sanitization.

Improper Control of Generation of Code ('Code Injection')

The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.

Improper Neutralization of Special Elements used in a Command ('Command Injection')

The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.

(function() {
    'use strict';
    exports.version = '3.0.0';

    var isEqual = require('lodash.isequal');
    var filterd = require('lodash.filter');
    var clonedeep = require('lodash.clonedeep');
    var matches = require('lodash.matches');

    function RuleEngine(rules, options) {
        this.init();
        if (typeof(rules) != "undefined") {
            this.register(rules);
        }
        if (options) {
            this.ignoreFactChanges = options.ignoreFactChanges;
        }
        return this;
    }
    RuleEngine.prototype.init = function(rules) {
        this.rules = [];
        this.activeRules = [];
    };
    RuleEngine.prototype.register = function(rules) {
        if (Array.isArray(rules)) {
            this.rules = this.rules.concat(rules);
        } else if (rules !== null && typeof(rules) == "object") {
            this.rules.push(rules);
        }
        this.sync();
    };
    RuleEngine.prototype.sync = function() {
        this.activeRules = this.rules.filter(function(a) {
            if (typeof(a.on) === "undefined") {
                a.on = true;
            }
            if (a.on === true) {
                return a;
            }
        });
        this.activeRules.sort(function(a, b) {
            if (a.priority && b.priority) {
                return b.priority - a.priority;
            } else {
                return 0;
            }
        });
    };
    RuleEngine.prototype.execute = function(fact, callback) {
        //these new attributes have to be in both last session and current session to support
        // the compare function
        var complete = false;
        fact.result = true;
        var session = clonedeep(fact);
        var lastSession = clonedeep(fact);
        var _rules = this.activeRules;
        var matchPath = [];
        var ignoreFactChanges = this.ignoreFactChanges;
        (function FnRuleLoop(x) {
            var API = {
                "rule": function() { return _rules[x]; },
                "when": function(outcome) {
                    if (outcome) {
                        var _consequence = _rules[x].consequence;
                        _consequence.ruleRef = _rules[x].id || _rules[x].name || 'index_'+x;
                        process.nextTick(function() {
                            matchPath.push(_consequence.ruleRef);
                            _consequence.call(session, API, session);
                        });
                    } else {
                        process.nextTick(function() {
                            API.next();
                        });
                    }
                },
                "restart": function() {
                    return FnRuleLoop(0);
                },
                "stop": function() {
                    complete = true;
                    return FnRuleLoop(0);
                },
                "next": function() {
                    if (!ignoreFactChanges && !isEqual(lastSession, session)) {
                        lastSession = clonedeep(session);
                        process.nextTick(function() {
                            API.restart();
                        });
                    } else {
                        process.nextTick(function() {
                            return FnRuleLoop(x + 1);
                        });
                    }
                }
            };
            if (x < _rules.length && complete === false) {
                var _rule = _rules[x].condition;
                _rule.call(session, API, session);
            } else {
                process.nextTick(function() {
                    session.matchPath = matchPath;
                    return callback(session);
                });
            }
        })(0);
    };
    RuleEngine.prototype.findRules = function(filter) {
        if (typeof(filter) === "undefined") {
            return this.rules;
        } else {
            var find = matches(filter);
            return filterd(this.rules, find);
        }
    }
    RuleEngine.prototype.turn = function(state, filter) {
        var state = (state === "on" || state === "ON") ? true : false;
        var rules = this.findRules(filter);
        for (var i = 0, j = rules.length; i < j; i++) {
            rules[i].on = state;
        }
        this.sync();
    }
    RuleEngine.prototype.prioritize = function(priority, filter) {
        priority = parseInt(priority, 10);
        var rules = this.findRules(filter);
        for (var i = 0, j = rules.length; i < j; i++) {
            rules[i].priority = priority;
        }
        this.sync();
    }
    RuleEngine.prototype.toJSON = function() {
        var rules = this.rules;
        if (rules instanceof Array) {
            rules = rules.map(function(rule) {
                rule.condition = rule.condition.toString();
                rule.consequence = rule.consequence.toString();
                return rule;
            });
        } else if (typeof(rules) != "undefined") {
            rules.condition = rules.condition.toString();
            rules.consequence = rules.consequence.toString();
        }
        return rules;
    };
    RuleEngine.prototype.fromJSON = function(rules) {
        this.init();
        if (typeof(rules) == "string") {
            rules = JSON.parse(rules);
        }
        if (rules instanceof Array) {
            rules = rules.map(function(rule) {
                rule.condition = eval("(" + rule.condition + ")");
                rule.consequence = eval("(" + rule.consequence + ")");
                return rule;
            });
        } else if (rules !== null && typeof(rules) == "object") {
            rules.condition = eval("(" + rules.condition + ")");
            rules.consequence = eval("(" + rules.consequence + ")");
        }
        this.register(rules);
    };
    module.exports = RuleEngine;
}(module.exports));

(function() {
    'use strict';
    exports.version = '3.0.0';

    var isEqual = require('lodash.isequal');
    var filterd = require('lodash.filter');
    var clonedeep = require('lodash.clonedeep');
    var matches = require('lodash.matches');

    function RuleEngine(rules, options) {
        this.init();
        if (typeof(rules) != "undefined") {
            this.register(rules);
        }
        if (options) {
            this.ignoreFactChanges = options.ignoreFactChanges;
        }
        return this;
    }
    RuleEngine.prototype.init = function(rules) {
        this.rules = [];
        this.activeRules = [];
    };
    RuleEngine.prototype.register = function(rules) {
        if (Array.isArray(rules)) {
            this.rules = this.rules.concat(rules);
        } else if (rules !== null && typeof(rules) == "object") {
            this.rules.push(rules);
        }
        this.sync();
    };
    RuleEngine.prototype.sync = function() {
        this.activeRules = this.rules.filter(function(a) {
            if (typeof(a.on) === "undefined") {
                a.on = true;
            }
            if (a.on === true) {
                return a;
            }
        });
        this.activeRules.sort(function(a, b) {
            if (a.priority && b.priority) {
                return b.priority - a.priority;
            } else {
                return 0;
            }
        });
    };
    RuleEngine.prototype.execute = function(fact, callback) {
        //these new attributes have to be in both last session and current session to support
        // the compare function
        var complete = false;
        fact.result = true;
        var session = clonedeep(fact);
        var lastSession = clonedeep(fact);
        var _rules = this.activeRules;
        var matchPath = [];
        var ignoreFactChanges = this.ignoreFactChanges;
        (function FnRuleLoop(x) {
            var API = {
                "rule": function() { return _rules[x]; },
                "when": function(outcome) {
                    if (outcome) {
                        var _consequence = _rules[x].consequence;
                        _consequence.ruleRef = _rules[x].id || _rules[x].name || 'index_'+x;
                        process.nextTick(function() {
                            matchPath.push(_consequence.ruleRef);
                            _consequence.call(session, API, session);
                        });
                    } else {
                        process.nextTick(function() {
                            API.next();
                        });
                    }
                },
                "restart": function() {
                    return FnRuleLoop(0);
                },
                "stop": function() {
                    complete = true;
                    return FnRuleLoop(0);
                },
                "next": function() {
                    if (!ignoreFactChanges && !isEqual(lastSession, session)) {
                        lastSession = clonedeep(session);
                        process.nextTick(function() {
                            API.restart();
                        });
                    } else {
                        process.nextTick(function() {
                            return FnRuleLoop(x + 1);
                        });
                    }
                }
            };
            if (x < _rules.length && complete === false) {
                var _rule = _rules[x].condition;
                _rule.call(session, API, session);
            } else {
                process.nextTick(function() {
                    session.matchPath = matchPath;
                    return callback(session);
                });
            }
        })(0);
    };
    RuleEngine.prototype.findRules = function(filter) {
        if (typeof(filter) === "undefined") {
            return this.rules;
        } else {
            var find = matches(filter);
            return filterd(this.rules, find);
        }
    }
    RuleEngine.prototype.turn = function(state, filter) {
        var state = (state === "on" || state === "ON") ? true : false;
        var rules = this.findRules(filter);
        for (var i = 0, j = rules.length; i < j; i++) {
            rules[i].on = state;
        }
        this.sync();
    }
    RuleEngine.prototype.prioritize = function(priority, filter) {
        priority = parseInt(priority, 10);
        var rules = this.findRules(filter);
        for (var i = 0, j = rules.length; i < j; i++) {
            rules[i].priority = priority;
        }
        this.sync();
    }
    module.exports = RuleEngine;
}(module.exports));

--- a/lib/node-rules.js
+++ b/lib/node-rules.js
@@ -128,36 +128,5 @@
         }
         this.sync();
     }
-    RuleEngine.prototype.toJSON = function() {
-        var rules = this.rules;
-        if (rules instanceof Array) {
-            rules = rules.map(function(rule) {
-                rule.condition = rule.condition.toString();
-                rule.consequence = rule.consequence.toString();
-                return rule;
-            });
-        } else if (typeof(rules) != "undefined") {
-            rules.condition = rules.condition.toString();
-            rules.consequence = rules.consequence.toString();
-        }
-        return rules;
-    };
-    RuleEngine.prototype.fromJSON = function(rules) {
-        this.init();
-        if (typeof(rules) == "string") {
-            rules = JSON.parse(rules);
-        }
-        if (rules instanceof Array) {
-            rules = rules.map(function(rule) {
-                rule.condition = eval("(" + rule.condition + ")");
-                rule.consequence = eval("(" + rule.consequence + ")");
-                return rule;
-            });
-        } else if (rules !== null && typeof(rules) == "object") {
-            rules.condition = eval("(" + rules.condition + ")");
-            rules.consequence = eval("(" + rules.consequence + ")");
-        }
-        this.register(rules);
-    };
     module.exports = RuleEngine;
 }(module.exports));


An incorrect implementation of "XEP-0280: Message Carbons" in multiple XMPP clients allows a remote attacker to impersonate any user, including contacts, in the vulnerable application's display. This allows for various kinds of social engineering attacks. This CVE is for jappix 1.0.0 to 1.1.6.

    self._getForwarded = function(message) {

        try {
            var forwarded_message = $(message.getNode()).find('forwarded[xmlns="' + NS_URN_FORWARD + '"]:first message:first');

            if(forwarded_message[0]) {
                return JSJaCPacket.wrapNode(forwarded_message[0]);
            }

            return null;
        } catch(e) {
            Console.error('Carbons._getForwarded', e);
        }

    };

    self._getForwarded = function(message) {

        try {
            // Check message is forwarded from our local user
            if(Common.bareXID(Common.getStanzaFrom(message)) == Common.getXID()) {
                var forwarded_message = $(message.getNode()).find('forwarded[xmlns="' + NS_URN_FORWARD + '"]:first message:first');

                if(forwarded_message[0]) {
                    return JSJaCPacket.wrapNode(forwarded_message[0]);
                }
            }

            return null;
        } catch(e) {
            Console.error('Carbons._getForwarded', e);
        }

    };

--- a/app/javascripts/carbons.js
+++ b/app/javascripts/carbons.js
@@ -1,10 +1,13 @@
     self._getForwarded = function(message) {

         try {
-            var forwarded_message = $(message.getNode()).find('forwarded[xmlns="' + NS_URN_FORWARD + '"]:first message:first');
+            // Check message is forwarded from our local user
+            if(Common.bareXID(Common.getStanzaFrom(message)) == Common.getXID()) {
+                var forwarded_message = $(message.getNode()).find('forwarded[xmlns="' + NS_URN_FORWARD + '"]:first message:first');

-            if(forwarded_message[0]) {
-                return JSJaCPacket.wrapNode(forwarded_message[0]);
+                if(forwarded_message[0]) {
+                    return JSJaCPacket.wrapNode(forwarded_message[0]);
+                }
             }

             return null;


Openshift allows remote attackers to gain privileges by updating a build configuration that was created with an allowed type to a type that is not allowed.

Improper Authorization

The product does not perform or incorrectly performs an authorization check when an actor attempts to access a resource or perform an action.

Execution with Unnecessary Privileges

The product performs an operation at a privilege level that is higher than the minimum level required, which creates new weaknesses or amplifies the consequences of other weaknesses.

Improper Privilege Management

The product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor.

func (a *buildByStrategy) Admit(attr admission.Attributes) error {
	if resource := attr.GetResource(); resource != buildsResource && resource != buildConfigsResource {
		return nil
	}
	switch obj := attr.GetObject().(type) {
	case *buildapi.Build:
		return a.checkBuildAuthorization(obj, attr)
	case *buildapi.BuildConfig:
		return a.checkBuildConfigAuthorization(obj, attr)
	case *buildapi.BuildRequest:
		return a.checkBuildRequestAuthorization(obj, attr)
	default:
		return admission.NewForbidden(attr, fmt.Errorf("unrecognized request object %#v", obj))
	}
}

func (a *buildByStrategy) Admit(attr admission.Attributes) error {
	if resource := attr.GetResource(); resource != buildsResource && resource != buildConfigsResource {
		return nil
	}
	// Explicitly exclude the builds/details subresource because it's only
	// updating commit info and cannot change build type.
	if attr.GetResource() == buildsResource && attr.GetSubresource() == "details" {
		return nil
	}
	switch obj := attr.GetObject().(type) {
	case *buildapi.Build:
		return a.checkBuildAuthorization(obj, attr)
	case *buildapi.BuildConfig:
		return a.checkBuildConfigAuthorization(obj, attr)
	case *buildapi.BuildRequest:
		return a.checkBuildRequestAuthorization(obj, attr)
	default:
		return admission.NewForbidden(attr, fmt.Errorf("unrecognized request object %#v", obj))
	}
}

--- a/pkg/build/admission/admission.go
+++ b/pkg/build/admission/admission.go
@@ -1,5 +1,10 @@
 func (a *buildByStrategy) Admit(attr admission.Attributes) error {
 	if resource := attr.GetResource(); resource != buildsResource && resource != buildConfigsResource {
+		return nil
+	}
+	// Explicitly exclude the builds/details subresource because it's only
+	// updating commit info and cannot change build type.
+	if attr.GetResource() == buildsResource && attr.GetSubresource() == "details" {
 		return nil
 	}
 	switch obj := attr.GetObject().(type) {