Embeding chatbot with iframe will expose the url #5266

Closed
opened 2026-02-21 18:10:11 -05:00 by yindo · 7 comments
Owner

Originally created by @taowang1993 on GitHub (Aug 28, 2024).

Self Checks

  • This is only for bug report, if you would like to ask a question, please head to Discussions.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report (我已阅读并同意 Language Policy).
  • [FOR CHINESE USERS] 请务必使用英文提交 Issue,否则会被关闭。谢谢!:)
  • Please do not modify this template :) and fill in all the required fields.

Dify version

0.7.2

Cloud or Self Hosted

Cloud

Steps to reproduce

If I embed this chatbot, technical users can just inspect the code and find the url.
Then, they can bypass paywall and use the chatbot.
How to prevent this?

✔️ Expected Behavior

No response

Actual Behavior

No response

Originally created by @taowang1993 on GitHub (Aug 28, 2024). ### Self Checks - [X] This is only for bug report, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general). - [X] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones. - [X] I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)). - [X] [FOR CHINESE USERS] 请务必使用英文提交 Issue,否则会被关闭。谢谢!:) - [X] Please do not modify this template :) and fill in all the required fields. ### Dify version 0.7.2 ### Cloud or Self Hosted Cloud ### Steps to reproduce If I embed this chatbot, technical users can just inspect the code and find the url. Then, they can bypass paywall and use the chatbot. How to prevent this? <iframe src="https://udify.app/chatbot/xxxxxxxxxxxxxxxxxx" style="width: 100%; height: 100%; min-height: 700px" frameborder="0" allow="microphone"> </iframe> ### ✔️ Expected Behavior _No response_ ### ❌ Actual Behavior _No response_
yindo closed this issue 2026-02-21 18:10:11 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Aug 28, 2024):

I found a similar open issue: Embedding Chatbot Will Expose URL, which was last updated on August 27, 2024 [1].

To prevent technical users from inspecting the code and finding the URL when embedding a chatbot with an iframe, you can obfuscate the URL and use server-side validation to ensure that only authorized users can access the chatbot. Here is a basic approach to achieve this:

  1. Obfuscate the URL: Encode the URL or use a token that is validated server-side.
  2. Server-side Validation: Ensure that the server validates the token or session to confirm that the user has access rights.

Here is an example of how you can modify the existing code to include these steps:

Step 1: Obfuscate the URL

You can use a function to encode the URL or generate a token that will be validated on the server.

async function getObfuscatedUrl(token, inputs) {
  const params = new URLSearchParams(inputs);
  const baseUrl = `https://${config.isDev ? "dev." : ""}udify.app`;
  const url = `${baseUrl}/chatbot/${token}?${params}`;
  
  // Encode the URL
  const encodedUrl = btoa(url);
  return encodedUrl;
}

Step 2: Modify the embedChatbot function to use the obfuscated URL

async function embedChatbot() {
  if (!config || !config.token) {
    console.error(`${configKey} is empty or token is not provided`);
    return;
  }

  const inputs = await getCompressedInputsFromConfig();
  const obfuscatedUrl = await getObfuscatedUrl(config.token, inputs);

  // Use the obfuscated URL
  const iframeUrl = `https://your-server.com/validate?url=${obfuscatedUrl}`;

  function createIframe() {
    const iframe = document.createElement("iframe");
    iframe.allow = "fullscreen;microphone";
    iframe.title = "dify chatbot bubble window";
    iframe.id = iframeId;
    iframe.src = iframeUrl;
    iframe.style.cssText = `
      border: none; position: fixed; flex-direction: column; justify-content: space-between;
      box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px;
      bottom: 5rem; right: 1rem; width: 24rem; max-width: calc(100vw - 2rem); height: 40rem;
      max-height: calc(100vh - 6rem); border-radius: 0.75rem; display: flex; z-index: 2147483647;
      overflow: hidden; left: unset; background-color: #F3F4F6;
    `;

    document.body.appendChild(iframe);
  }

  createButton();
}

Step 3: Server-side Validation

On your server, you should have an endpoint that validates the obfuscated URL and returns the actual URL if the user is authorized.

from flask import Flask, request, jsonify
import base64

app = Flask(__name__)

@app.route('/validate', methods=['GET'])
def validate():
    obfuscated_url = request.args.get('url')
    if not obfuscated_url:
        return jsonify({"error": "Invalid request"}), 400

    # Decode the URL
    decoded_url = base64.b64decode(obfuscated_url).decode('utf-8')

    # Perform your validation logic here
    if user_is_authorized():
        return jsonify({"url": decoded_url})
    else:
        return jsonify({"error": "Unauthorized"}), 403

def user_is_authorized():
    # Implement your authorization logic here
    return True

if __name__ == '__main__':
    app.run()

Additionally, you can use the Dify platform's built-in capabilities to manage the embedding of chatbots securely. Dify provides various embedding options such as iframe, scripts, and Chrome plugins, which can be customized and secured as needed. Here is an example of how you can use Dify's embedding options:

const OPTION_MAP = {
  iframe: {
    getContent: (url: string, token: string) =>
      `<iframe
 src="${url}/chatbot/${token}"
 style="width: 100%; height: 100%; min-height: 700px"
 frameborder="0"
 allow="microphone">
</iframe>`,
  },
  scripts: {
    getContent: (url: string, token: string, primaryColor: string, isTestEnv?: boolean) =>
      `<script>
 window.difyChatbotConfig = {
  token: '${token}'${isTestEnv
  ? `,
  isDev: true`
  : ''}${IS_CE_EDITION
  ? `,
  baseUrl: '${url}'`
  : ''}
 }
</script>
<script
 src="${url}/embed.min.js"
 id="${token}"
 defer>
</script>
<style>
  #dify-chatbot-bubble-button {
    background-color: ${primaryColor} !important;
  }
</style>`,
  },
  chromePlugin: {
    getContent: (url: string, token: string) => `ChatBot URL: ${url}/chatbot/${token}`,
  },
}

By following these steps and leveraging Dify's features, you can help prevent technical users from easily inspecting the code and finding the URL, thus avoiding bypassing the paywall [2][3].

To continue talking to Dosu, mention @dosu.

@dosubot[bot] commented on GitHub (Aug 28, 2024): <!-- Answer --> I found a similar open issue: [Embedding Chatbot Will Expose URL](https://github.com/langgenius/dify/issues/7551), which was last updated on August 27, 2024 <sup>[[1]](https://github.com/langgenius/dify/issues/7551)</sup>. To prevent technical users from inspecting the code and finding the URL when embedding a chatbot with an iframe, you can obfuscate the URL and use server-side validation to ensure that only authorized users can access the chatbot. Here is a basic approach to achieve this: 1. **Obfuscate the URL**: Encode the URL or use a token that is validated server-side. 2. **Server-side Validation**: Ensure that the server validates the token or session to confirm that the user has access rights. Here is an example of how you can modify the existing code to include these steps: ### Step 1: Obfuscate the URL You can use a function to encode the URL or generate a token that will be validated on the server. ```js async function getObfuscatedUrl(token, inputs) { const params = new URLSearchParams(inputs); const baseUrl = `https://${config.isDev ? "dev." : ""}udify.app`; const url = `${baseUrl}/chatbot/${token}?${params}`; // Encode the URL const encodedUrl = btoa(url); return encodedUrl; } ``` ### Step 2: Modify the `embedChatbot` function to use the obfuscated URL ```js async function embedChatbot() { if (!config || !config.token) { console.error(`${configKey} is empty or token is not provided`); return; } const inputs = await getCompressedInputsFromConfig(); const obfuscatedUrl = await getObfuscatedUrl(config.token, inputs); // Use the obfuscated URL const iframeUrl = `https://your-server.com/validate?url=${obfuscatedUrl}`; function createIframe() { const iframe = document.createElement("iframe"); iframe.allow = "fullscreen;microphone"; iframe.title = "dify chatbot bubble window"; iframe.id = iframeId; iframe.src = iframeUrl; iframe.style.cssText = ` border: none; position: fixed; flex-direction: column; justify-content: space-between; box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px; bottom: 5rem; right: 1rem; width: 24rem; max-width: calc(100vw - 2rem); height: 40rem; max-height: calc(100vh - 6rem); border-radius: 0.75rem; display: flex; z-index: 2147483647; overflow: hidden; left: unset; background-color: #F3F4F6; `; document.body.appendChild(iframe); } createButton(); } ``` ### Step 3: Server-side Validation On your server, you should have an endpoint that validates the obfuscated URL and returns the actual URL if the user is authorized. ```python from flask import Flask, request, jsonify import base64 app = Flask(__name__) @app.route('/validate', methods=['GET']) def validate(): obfuscated_url = request.args.get('url') if not obfuscated_url: return jsonify({"error": "Invalid request"}), 400 # Decode the URL decoded_url = base64.b64decode(obfuscated_url).decode('utf-8') # Perform your validation logic here if user_is_authorized(): return jsonify({"url": decoded_url}) else: return jsonify({"error": "Unauthorized"}), 403 def user_is_authorized(): # Implement your authorization logic here return True if __name__ == '__main__': app.run() ``` Additionally, you can use the Dify platform's built-in capabilities to manage the embedding of chatbots securely. Dify provides various embedding options such as iframe, scripts, and Chrome plugins, which can be customized and secured as needed. Here is an example of how you can use Dify's embedding options: ```tsx const OPTION_MAP = { iframe: { getContent: (url: string, token: string) => `<iframe src="${url}/chatbot/${token}" style="width: 100%; height: 100%; min-height: 700px" frameborder="0" allow="microphone"> </iframe>`, }, scripts: { getContent: (url: string, token: string, primaryColor: string, isTestEnv?: boolean) => `<script> window.difyChatbotConfig = { token: '${token}'${isTestEnv ? `, isDev: true` : ''}${IS_CE_EDITION ? `, baseUrl: '${url}'` : ''} } </script> <script src="${url}/embed.min.js" id="${token}" defer> </script> <style> #dify-chatbot-bubble-button { background-color: ${primaryColor} !important; } </style>`, }, chromePlugin: { getContent: (url: string, token: string) => `ChatBot URL: ${url}/chatbot/${token}`, }, } ``` By following these steps and leveraging Dify's features, you can help prevent technical users from easily inspecting the code and finding the URL, thus avoiding bypassing the paywall <sup>[[2]](https://github.com/langgenius/dify/blob/main/web/public/embed.js)</sup><sup>[[3]](https://github.com/langgenius/dify/blob/main/web/app/components/app/overview/embedded/index.tsx)</sup>. <!-- Dosu Comment Footer --> *To continue talking to [Dosu](https://dosu.dev), mention @dosu.*
Author
Owner

@crazywoola commented on GitHub (Sep 4, 2024):

This is an expected behavior.

@crazywoola commented on GitHub (Sep 4, 2024): This is an expected behavior.
Author
Owner

@taowang1993 commented on GitHub (Sep 4, 2024):

Is it possible to configure CORS to only allow my own domain to embed the chatbot?

If others find out my chatbot url, they can embed it on their website and consume my tokens.

@taowang1993 commented on GitHub (Sep 4, 2024): Is it possible to configure CORS to only allow my own domain to embed the chatbot? If others find out my chatbot url, they can embed it on their website and consume my tokens.
Author
Owner

@taowang1993 commented on GitHub (Sep 4, 2024):

This is an expected behavior.

Is this going to be fixed in near future? I don't want others embed my chatbot.

@taowang1993 commented on GitHub (Sep 4, 2024): > This is an expected behavior. Is this going to be fixed in near future? I don't want others embed my chatbot.
Author
Owner

@GoulartNogueira commented on GitHub (Sep 6, 2024):

It will probably not be "fixed" as it's not "broken".
That's how iframe works, not an issue with Dify.

If you want to protect your chatbot, I suggest one of 2 ways:

  1. Deploy your application with another approach other than iframe.
  2. Keep using iframe, but use some security method inside dify to make sure the user is authenticated. For example: Create a key, set a lifetime to it, store it in your backend. Inject it into the iframe with window.difyChatbotConfig. Then inside your bot, before calling any LLM you must always call an API to check if the key is valid.

Either way, you must pick some kind of complexity.
I'd recommend the first.

@GoulartNogueira commented on GitHub (Sep 6, 2024): It will probably not be "fixed" as it's not "broken". [That's how iframe works](https://stackoverflow.com/questions/69324577/how-to-hide-src-attribute-value-url-in-iframe-tag), not an issue with Dify. If you want to protect your chatbot, I suggest one of 2 ways: 1. Deploy your application with [another approach](https://docs.dify.ai/guides/application-publishing) other than iframe. 2. Keep using iframe, but use some security method inside dify to make sure the user is authenticated. For example: Create a key, set a lifetime to it, store it in your backend. Inject it into the iframe with `window.difyChatbotConfig`. Then inside your bot, before calling any LLM you must always call an API to check if the key is valid. Either way, you must pick some kind of complexity. I'd recommend the first.
Author
Owner

@taowang1993 commented on GitHub (Sep 6, 2024):

Flowise has this secure approach of embedding chatbot.

<flowise-fullchatbot></flowise-fullchatbot>
<script type="module">
    import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
    Chatbot.init({
        chatflowid: "f5adc8af-d9e3-4735-af79-886f237",
        apiHost: "https://taowang1993-flowise.hf.space",
    })
</script>

Then, you can set up Allowed Domains for embedding your chatbot. So, only your website can embed your chatbot.

image

I wish Dify has this as well. I would love to make contributions, but I am not very technical.

@taowang1993 commented on GitHub (Sep 6, 2024): Flowise has this secure approach of embedding chatbot. ```code <flowise-fullchatbot></flowise-fullchatbot> <script type="module"> import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js" Chatbot.init({ chatflowid: "f5adc8af-d9e3-4735-af79-886f237", apiHost: "https://taowang1993-flowise.hf.space", }) </script> ``` Then, you can set up Allowed Domains for embedding your chatbot. So, only your website can embed your chatbot. <img width="892" alt="image" src="https://github.com/user-attachments/assets/f7aa7f1c-dfa7-41e9-b279-fae433835861"> I wish Dify has this as well. I would love to make contributions, but I am not very technical.
Author
Owner

@ManasN commented on GitHub (Aug 27, 2025):

I am surprised not many people are facing an issue in this regard. What @taowang1993 has posted seems indeed a sane approach to me, any update on this?

@ManasN commented on GitHub (Aug 27, 2025): I am surprised not many people are facing an issue in this regard. What @taowang1993 has posted seems indeed a sane approach to me, any update on this?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#5266