diff --git a/package.json b/package.json
index 0e9d63abf9..5ce0a0e637 100644
--- a/package.json
+++ b/package.json
@@ -80,6 +80,7 @@
"@swc/core": "^1.7.14",
"@swc/jest": "^0.2.36",
"@testing-library/react-hooks": "^8.0.1",
+ "@types/eslint": "^9.6.1",
"@types/fs-extra": "^9.0.13",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.14.197",
diff --git a/packages/eslint-plugin/src/rules/__tests__/no-hardcoded-src.test.ts b/packages/eslint-plugin/src/rules/__tests__/no-hardcoded-src.test.ts
new file mode 100644
index 0000000000..91cb4b8564
--- /dev/null
+++ b/packages/eslint-plugin/src/rules/__tests__/no-hardcoded-src.test.ts
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+import {TSESLint} from '@typescript-eslint/utils';
+import rule from '../no-hardcoded-src';
+
+declare const require: any;
+
+const ruleTester = new TSESLint.RuleTester({
+ parser: require.resolve('@typescript-eslint/parser'),
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+});
+
+ruleTester.run('no-hardcoded-src', rule, {
+ valid: [
+ {code: `
`},
+ {
+ code: `import useBaseUrl from '@docusaurus/useBaseUrl';\n
`,
+ },
+ {code: `
`,
+ errors: [{messageId: 'hardcodedSrc'}],
+ },
+ {code: `
`, errors: [{messageId: 'hardcodedSrc'}]},
+ ],
+});
diff --git a/packages/eslint-plugin/src/rules/no-hardcoded-src.ts b/packages/eslint-plugin/src/rules/no-hardcoded-src.ts
new file mode 100644
index 0000000000..dc087a37b3
--- /dev/null
+++ b/packages/eslint-plugin/src/rules/no-hardcoded-src.ts
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+import {createRule} from '../util';
+import type {TSESTree} from '@typescript-eslint/utils';
+
+export default createRule({
+ name: 'no-hardcoded-src',
+ meta: {
+ type: 'problem',
+ docs: {
+ description:
+ 'Enforce using require() or useBaseUrl() for src attributes.',
+ recommended: 'warn',
+ },
+ schema: [],
+ messages: {
+ hardcodedSrc:
+ 'Do not use a hardcoded string for the src attribute. Use require() or useBaseUrl() for image paths instead.',
+ },
+ },
+ defaultOptions: [],
+ create(context) {
+ return {
+ JSXOpeningElement(node: TSESTree.JSXOpeningElement) {
+ if (node.name.type !== 'JSXIdentifier' || node.name.name !== 'img') {
+ return;
+ }
+
+ const srcAttribute = node.attributes.find(
+ (attr): attr is TSESTree.JSXAttribute =>
+ attr.type === 'JSXAttribute' && attr.name.name === 'src',
+ );
+
+ if (!srcAttribute) {
+ return;
+ }
+
+ if (
+ srcAttribute.value?.type === 'Literal' &&
+ typeof srcAttribute.value.value === 'string' &&
+ srcAttribute.value.value.trim().length > 0
+ ) {
+ context.report({
+ node: srcAttribute,
+ messageId: 'hardcodedSrc',
+ });
+ }
+ },
+ };
+ },
+});
diff --git a/yarn.lock b/yarn.lock
index 23c7994f16..ce4e0e4020 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4243,6 +4243,14 @@
resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-1.0.4.tgz#dc7c166b76c7b03b27e32f80edf01d91eb5d9af2"
integrity sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==
+"@types/eslint@^9.6.1":
+ version "9.6.1"
+ resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.1.tgz#d5795ad732ce81715f27f75da913004a56751584"
+ integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==
+ dependencies:
+ "@types/estree" "*"
+ "@types/json-schema" "*"
+
"@types/estree-jsx@^1.0.0":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-1.0.5.tgz#858a88ea20f34fe65111f005a689fa1ebf70dc18"
@@ -4432,7 +4440,7 @@
"@types/tough-cookie" "*"
parse5 "^7.0.0"
-"@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
+"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
version "7.0.15"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==